Utilize InputMethodSubtype and additional subtype

* Remove de_QY and fr_CH from supported subtypes
* Add de-qwerty and fr-qwertz predefined additional subtypes instead.

Change-Id: I49e8ba0299529302f2b91b4d018b07304cdd6897
main
Tadashi G. Takaoka 2012-04-11 18:21:10 +09:00
parent f338f8b50d
commit f6972561fc
14 changed files with 305 additions and 201 deletions

View File

@ -134,24 +134,24 @@
<item>5</item>
</string-array>
<!-- Subtype locale name exceptions -->
<!-- Subtype locale display name exceptions -->
<string-array name="subtype_locale_exception_keys">
<item>en_US</item>
<item>en_GB</item>
<item>*_QY</item>
<item>QY</item>
</string-array>
<string-array name="subtype_locale_exception_values">
<item>English (US)</item>
<item>English (UK)</item>
<item>@string/subtype_generic_qwerty</item>
<item>QWERTY</item>
</string-array>
<!-- Generic subtype label -->
<string name="subtype_generic">%s</string>
<!-- Description for generic QWERTY keyboard subtype -->
<string name="subtype_generic_qwerty">%s (QWERTY)</string>
<!-- Description for generic QWERTZ keyboard subtype -->
<string name="subtype_generic_qwertz">%s (QWERTZ)</string>
<!-- Description for generic AZERTY keyboard subtype -->
<string name="subtype_generic_azerty">%s (AZERTY)</string>
<!-- dictionary pack package name /settings activity (for shared prefs and settings) -->
<string name="dictionary_pack_package_name">com.google.android.inputmethod.latin.dictionarypack</string>

View File

@ -28,7 +28,6 @@
cs: Czech/qwertz
da: Danish/nordic
de: German/qwertz
de_QY: German (QWERTY)/qwerty
el: Greek/greek
en_US: English United States/qwerty
en_GB: English Great Britain/qwerty
@ -38,7 +37,6 @@
fi: Finnish/nordic
fr: French/azerty
fr_CA: French Canada/qwerty
fr_CH: French Switzerland/qwertz
hi: Hindi/hindi
hr: Croatian/qwertz
hu: Hungarian/qwertz
@ -64,7 +62,7 @@
tr: Turkish/qwerty
uk: Ukrainian/east_slavic
vi: Vietnamese/qwerty
zz_QY: QWERTY/qwerty
zz: QWERTY/qwerty
-->
<!-- TODO: use <lang>_keyboard icon instead of a common keyboard icon. -->
<!-- If IME doesn't have an applicable subtype, the first subtype will be used as a default
@ -120,12 +118,6 @@
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwertz,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic_qwerty"
android:imeSubtypeLocale="de"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty:de_QY,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
android:imeSubtypeLocale="el"
@ -168,12 +160,6 @@
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
android:imeSubtypeLocale="fr_CH"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwertz,AsciiCapable"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
android:imeSubtypeLocale="hi"
@ -327,7 +313,7 @@
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_no_language_qwerty"
android:imeSubtypeLocale="zz_QY"
android:imeSubtypeLocale="zz"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EnabledWhenDefaultIsNotAsciiCapable"
/>

View File

@ -53,6 +53,10 @@ public class InputMethodManagerCompatWrapper {
sInstance.mImm = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);
}
public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
mImm.setAdditionalInputMethodSubtypes(imiId, subtypes);
}
public InputMethodSubtype getCurrentInputMethodSubtype() {
return mImm.getCurrentInputMethodSubtype();
}

View File

@ -793,7 +793,7 @@ public class Keyboard {
}
};
// Null means the current system locale.
final Locale locale = language.equals(SubtypeLocale.NO_LANGUAGE)
final Locale locale = SubtypeLocale.isNoLanguage(params.mId.mSubtype)
? null : params.mId.mLocale;
job.runInLocale(mResources, locale);

View File

@ -19,9 +19,12 @@ package com.android.inputmethod.keyboard;
import android.text.InputType;
import android.text.TextUtils;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.compat.EditorInfoCompatUtils;
import com.android.inputmethod.latin.InputTypeUtils;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.SubtypeLocale;
import java.util.Arrays;
import java.util.Locale;
@ -53,6 +56,7 @@ public class KeyboardId {
private static final int IME_ACTION_CUSTOM_LABEL = EditorInfo.IME_MASK_ACTION + 1;
public final InputMethodSubtype mSubtype;
public final Locale mLocale;
public final int mOrientation;
public final int mWidth;
@ -67,10 +71,11 @@ public class KeyboardId {
private final int mHashCode;
public KeyboardId(int elementId, Locale locale, int orientation, int width, int mode,
EditorInfo editorInfo, boolean clobberSettingsKey, boolean shortcutKeyEnabled,
public KeyboardId(int elementId, InputMethodSubtype subtype, int orientation, int width,
int mode, EditorInfo editorInfo, boolean clobberSettingsKey, boolean shortcutKeyEnabled,
boolean hasShortcutKey, boolean languageSwitchKeyEnabled) {
mLocale = locale;
mSubtype = subtype;
mLocale = SubtypeLocale.getSubtypeLocale(subtype);
mOrientation = orientation;
mWidth = width;
mMode = mode;
@ -102,7 +107,7 @@ public class KeyboardId {
id.mCustomActionLabel,
id.navigateNext(),
id.navigatePrevious(),
id.mLocale
id.mSubtype
});
}
@ -123,7 +128,7 @@ public class KeyboardId {
&& TextUtils.equals(other.mCustomActionLabel, mCustomActionLabel)
&& other.navigateNext() == navigateNext()
&& other.navigatePrevious() == navigatePrevious()
&& other.mLocale.equals(mLocale);
&& other.mSubtype.equals(mSubtype);
}
public boolean isAlphabetKeyboard() {
@ -176,9 +181,10 @@ public class KeyboardId {
@Override
public String toString() {
return String.format("[%s %s %s%d %s %s %s%s%s%s%s%s%s%s]",
return String.format("[%s %s:%s %s%d %s %s %s%s%s%s%s%s%s%s]",
elementIdToName(mElementId),
mLocale,
mSubtype.getExtraValueOf(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET),
(mOrientation == 1 ? "port" : "land"), mWidth,
modeName(mMode),
imeAction(),

View File

@ -44,7 +44,6 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Locale;
/**
* This class represents a set of keyboard layouts. Each of them represents a different keyboard
@ -109,7 +108,7 @@ public class KeyboardLayoutSet {
boolean mVoiceKeyOnMain;
boolean mNoSettingsKey;
boolean mLanguageSwitchKeyEnabled;
Locale mLocale;
InputMethodSubtype mSubtype;
int mOrientation;
int mWidth;
// KeyboardLayoutSet element id to element's parameters map.
@ -203,10 +202,10 @@ public class KeyboardLayoutSet {
final Params params = mParams;
final boolean isSymbols = (keyboardLayoutSetElementId == KeyboardId.ELEMENT_SYMBOLS
|| keyboardLayoutSetElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED);
final boolean noLanguage = params.mLocale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE);
final boolean noLanguage = SubtypeLocale.isNoLanguage(params.mSubtype);
final boolean voiceKeyEnabled = params.mVoiceKeyEnabled && !noLanguage;
final boolean hasShortcutKey = voiceKeyEnabled && (isSymbols != params.mVoiceKeyOnMain);
return new KeyboardId(keyboardLayoutSetElementId, params.mLocale, params.mOrientation,
return new KeyboardId(keyboardLayoutSetElementId, params.mSubtype, params.mOrientation,
params.mWidth, params.mMode, params.mEditorInfo, params.mNoSettingsKey,
voiceKeyEnabled, hasShortcutKey, params.mLanguageSwitchKeyEnabled);
}
@ -251,7 +250,7 @@ public class KeyboardLayoutSet {
final InputMethodSubtype keyboardSubtype = (forceAscii && !asciiCapable)
? SubtypeSwitcher.getInstance().getNoLanguageSubtype()
: subtype;
mParams.mLocale = SubtypeLocale.getKeyboardLayoutSetLocale(keyboardSubtype);
mParams.mSubtype = keyboardSubtype;
mParams.mKeyboardLayoutSetName = KEYBOARD_LAYOUT_SET_RESOURCE_PREFIX
+ SubtypeLocale.getKeyboardLayoutSetName(keyboardSubtype);
return this;
@ -278,7 +277,7 @@ public class KeyboardLayoutSet {
public KeyboardLayoutSet build() {
if (mParams.mOrientation == Configuration.ORIENTATION_UNDEFINED)
throw new RuntimeException("Screen geometry is not specified");
if (mParams.mLocale == null)
if (mParams.mSubtype == null)
throw new RuntimeException("KeyboardLayoutSet subtype is not specified");
final String packageName = mResources.getResourcePackageName(
R.xml.keyboard_layout_set_qwerty);

View File

@ -35,6 +35,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodSubtype;
import android.widget.PopupWindow;
import com.android.inputmethod.accessibility.AccessibilityUtils;
@ -52,7 +53,6 @@ import com.android.inputmethod.latin.Utils;
import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils;
import com.android.inputmethod.latin.define.ProductionFlag;
import java.util.Locale;
import java.util.WeakHashMap;
/**
@ -80,7 +80,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator;
private static final int ALPHA_OPAQUE = 255;
private boolean mNeedsToDisplayLanguage;
private Locale mSpacebarLocale;
private int mLanguageOnSpacebarAnimAlpha = ALPHA_OPAQUE;
private final float mSpacebarTextRatio;
private float mSpacebarTextSize;
@ -468,7 +467,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
mSpaceIcon = (mSpaceKey != null) ? mSpaceKey.getIcon(keyboard.mIconsSet) : null;
final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
mSpacebarTextSize = keyHeight * mSpacebarTextRatio;
mSpacebarLocale = keyboard.mId.mLocale;
}
/**
@ -904,12 +902,12 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
}
// Layout locale language name on spacebar.
private String layoutLanguageOnSpacebar(Paint paint, Locale locale, int width,
private String layoutLanguageOnSpacebar(Paint paint, InputMethodSubtype subtype, int width,
float origTextSize) {
paint.setTextAlign(Align.CENTER);
paint.setTypeface(Typeface.DEFAULT);
// Estimate appropriate language name text size to fit in maxTextWidth.
String language = SubtypeLocale.getFullDisplayName(locale);
String language = SubtypeLocale.getFullDisplayName(subtype);
int textWidth = getTextWidth(paint, language, origTextSize);
// Assuming text width and text size are proportional to each other.
float textSize = origTextSize * Math.min(width / textWidth, 1.0f);
@ -921,7 +919,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
final boolean useShortName;
if (useMiddleName) {
language = SubtypeLocale.getMiddleDisplayName(locale);
language = SubtypeLocale.getMiddleDisplayName(subtype);
textWidth = getTextWidth(paint, language, origTextSize);
textSize = origTextSize * Math.min(width / textWidth, 1.0f);
useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME)
@ -931,7 +929,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
}
if (useShortName) {
language = SubtypeLocale.getShortDisplayName(locale);
language = SubtypeLocale.getShortDisplayName(subtype);
textWidth = getTextWidth(paint, language, origTextSize);
textSize = origTextSize * Math.min(width / textWidth, 1.0f);
}
@ -944,10 +942,10 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
final int width = key.mWidth;
final int height = key.mHeight;
// If input subtypes are explicitly selected.
// If input language are explicitly selected.
if (mNeedsToDisplayLanguage) {
final String language = layoutLanguageOnSpacebar(paint, mSpacebarLocale, width,
mSpacebarTextSize);
final String language = layoutLanguageOnSpacebar(
paint, getKeyboard().mId.mSubtype, width, mSpacebarTextSize);
// Draw language text with shadow
// In case there is no space icon, we will place the language text at the center of
// spacebar.

View File

@ -0,0 +1,56 @@
/*
* 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.view.inputmethod.InputMethodSubtype;
import java.util.HashMap;
import java.util.Locale;
public class AdditionalSubtype {
public static final String QWERTY = "qwerty";
public static final String QWERTZ = "qwertz";
public static final String AZERTY = "azerty";
private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
private static final String SUBTYPE_EXTRA_VALUE_IS_ADDITIONAL_SUBTYPE = "isAdditionalSubtype";
// Keyboard layout to subtype name resource id map.
private static final HashMap<String, Integer> sKeyboardLayoutToNameIdsMap =
new HashMap<String, Integer>();
static {
sKeyboardLayoutToNameIdsMap.put(QWERTY, R.string.subtype_generic_qwerty);
sKeyboardLayoutToNameIdsMap.put(QWERTZ, R.string.subtype_generic_qwertz);
sKeyboardLayoutToNameIdsMap.put(AZERTY, R.string.subtype_generic_azerty);
}
public static boolean isAdditionalSubtype(InputMethodSubtype subtype) {
return subtype.containsExtraValueKey(SUBTYPE_EXTRA_VALUE_IS_ADDITIONAL_SUBTYPE);
}
public static InputMethodSubtype createAddtionalSubtype(
Locale locale, String keyboardLayoutSet) {
final String extraValue = String.format(
"%s=%s,%s", LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET, keyboardLayoutSet,
SUBTYPE_EXTRA_VALUE_IS_ADDITIONAL_SUBTYPE);
Integer nameId = sKeyboardLayoutToNameIdsMap.get(keyboardLayoutSet);
if (nameId == null) nameId = R.string.subtype_generic;
return new InputMethodSubtype(nameId, R.drawable.ic_subtype_keyboard,
locale.toString(), SUBTYPE_MODE_KEYBOARD, extraValue, false, false);
}
}

View File

@ -439,6 +439,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
loadSettings();
mImm.setAdditionalInputMethodSubtypes(
SubtypeUtils.getInputMethodId(getPackageName()),
mSettingsValues.getPrefefinedAdditionalSubtypes());
// TODO: remove the following when it's not needed by updateCorrectionMode() any more
mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */);
updateCorrectionMode();

View File

@ -21,12 +21,14 @@ import android.content.SharedPreferences;
import android.content.res.Resources;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.keyboard.internal.KeySpecParser;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
/**
* When you call the constructor of this class, you may want to change the current system locale by
@ -69,6 +71,7 @@ public class SettingsValues {
private final int mVibrationDurationSettingsRawValue;
@SuppressWarnings("unused") // TODO: Use this
private final float mKeypressSoundVolumeRawValue;
private final InputMethodSubtype[] mPredefinedAdditionalSubtypes;
// Deduced settings
public final int mKeypressVibrationDuration;
@ -145,6 +148,16 @@ public class SettingsValues {
mAutoCorrectionThresholdRawValue);
mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff);
mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain);
// Predefined additional subtypes
final InputMethodSubtype DE_QWERTY = AdditionalSubtype.createAddtionalSubtype(
Locale.GERMAN, AdditionalSubtype.QWERTY);
final InputMethodSubtype FR_QWERTZ = AdditionalSubtype.createAddtionalSubtype(
Locale.FRENCH, AdditionalSubtype.QWERTZ);
mPredefinedAdditionalSubtypes = new InputMethodSubtype[] {
DE_QWERTY,
FR_QWERTZ,
};
}
// Helper functions to create member values.
@ -304,6 +317,11 @@ public class SettingsValues {
return res.getBoolean(R.bool.config_use_fullscreen_mode);
}
// TODO: Should be able to add/remove/edit.
public InputMethodSubtype[] getPrefefinedAdditionalSubtypes() {
return mPredefinedAdditionalSubtypes;
}
// Accessed from the settings interface, hence public
public static float getCurrentKeypressSoundVolume(final SharedPreferences sp,
final Resources res) {

View File

@ -20,23 +20,17 @@ import android.content.Context;
import android.content.res.Resources;
import android.view.inputmethod.InputMethodSubtype;
import java.util.HashMap;
import java.util.Locale;
public class SubtypeLocale {
// Special language code to represent "no language".
public static final String NO_LANGUAGE = "zz";
// Special country code to represent "QWERTY".
/* package for test */ static final String QWERTY = "QY";
private static final String NO_LANGUAGE = "zz";
public static final Locale LOCALE_NO_LANGUAGE = new Locale(NO_LANGUAGE);
public static final Locale LOCALE_NO_LANGUAGE_QWERTY = new Locale(NO_LANGUAGE, QWERTY);
private static String[] sExceptionKeys;
private static String[] sExceptionValues;
private static final String DEFAULT_KEYBOARD_LAYOUT_SET = "qwerty";
private static final char KEYBOARD_LAYOUT_SET_LOCALE_DELIMITER = ':';
// Exceptional locales to display name map.
private static final HashMap<String, String> sExceptionalDisplayNamesMap =
new HashMap<String, String>();
private SubtypeLocale() {
// Intentional empty constructor for utility class.
@ -44,72 +38,74 @@ public class SubtypeLocale {
public static void init(Context context) {
final Resources res = context.getResources();
sExceptionKeys = res.getStringArray(R.array.subtype_locale_exception_keys);
sExceptionValues = res.getStringArray(R.array.subtype_locale_exception_values);
}
private static String lookupExceptionalLocale(String key) {
for (int index = 0; index < sExceptionKeys.length; index++) {
if (sExceptionKeys[index].equals(key)) {
return sExceptionValues[index];
}
}
return null;
}
// Get Locale's full display name in its locale.
// For example:
// "fr_CH" is converted to "Français (Suisse)".
// "de_QY" is converted to "Deutsche (QWERTY)". (Any locale that has country code "QY")
// "zz_QY" is converted to "QWERTY". (The language code "zz" means "No language", thus just
// ends up with the keyboard layout name.)
public static String getFullDisplayName(Locale locale) {
final String key;
if (locale.getLanguage().equals(NO_LANGUAGE)) {
key = locale.getCountry();
} else if (locale.getCountry().equals(QWERTY)) {
key = "*_" + QWERTY;
} else {
key = locale.toString();
}
final String value = lookupExceptionalLocale(key);
if (value == null) {
return StringUtils.toTitleCase(locale.getDisplayName(locale), locale);
}
if (value.indexOf("%s") >= 0) {
final String languageName = StringUtils.toTitleCase(
locale.getDisplayLanguage(locale), locale);
return String.format(value, languageName);
}
return value;
}
// Get Locale's middle display name in its locale.
// For example:
// "fr_CH" is converted to "Français".
// "de_QY" is converted to "Deutsche". (Any locale that has country code "QY")
// "zz_QY" is converted to "QWERTY". (The language code "zz" means "No language", thus just
// ends up with the keyboard layout name.)
public static String getMiddleDisplayName(Locale locale) {
if (NO_LANGUAGE.equals(locale.getLanguage())) {
return lookupExceptionalLocale(locale.getCountry());
} else {
return StringUtils.toTitleCase(locale.getDisplayLanguage(locale), locale);
final String[] locales = res.getStringArray(R.array.subtype_locale_exception_keys);
final String[] displayNames = res.getStringArray(R.array.subtype_locale_exception_values);
for (int i = 0; i < locales.length; i++) {
sExceptionalDisplayNamesMap.put(locales[i], displayNames[i]);
}
}
// Get Locale's short display name in its locale.
// For example:
// "fr_CH" is converted to "Fr".
// "de_QY" is converted to "De". (Any locale that has country code "QY")
// "zz_QY" is converter to "QY". (The language code "zz" means "No language", thus just ends
// up with the keyboard layout name.)
public static String getShortDisplayName(Locale locale) {
if (NO_LANGUAGE.equals(locale.getLanguage())) {
return locale.getCountry();
} else {
return StringUtils.toTitleCase(locale.getLanguage(), locale);
// Get InputMethodSubtype's display name in its locale.
// isAdditionalSubtype (T=true, F=false)
// locale layout | Short Middle Full
// ------ ------ - ---- --------- -----------------
// en_US qwerty F En English English (US) exception
// en_GB qwerty F En English English (UK) exception
// fr azerty F Fr Français Français
// fr_CA qwerty F Fr Français Français (Canada)
// de qwertz F De Deutsch Deutsch
// zz qwerty F QWERTY QWERTY
// fr qwertz T Fr Français Français (QWERTZ)
// de qwerty T De Deutsch Deutsch (QWERTY)
// en azerty T En English English (AZERTY)
// zz azerty T AZERTY AZERTY
// Get InputMethodSubtype's full display name in its locale.
public static String getFullDisplayName(InputMethodSubtype subtype) {
final String value = sExceptionalDisplayNamesMap.get(subtype.getLocale());
if (value != null) {
return value;
}
if (isNoLanguage(subtype)) {
return getKeyboardLayoutSetName(subtype).toUpperCase();
}
final Locale locale = getSubtypeLocale(subtype);
final String language = StringUtils.toTitleCase(locale.getDisplayLanguage(locale), locale);
if (AdditionalSubtype.isAdditionalSubtype(subtype)) {
return String.format("%s (%s)",
language, getKeyboardLayoutSetName(subtype).toUpperCase());
}
return StringUtils.toTitleCase(locale.getDisplayName(locale), locale);
}
// Get InputMethodSubtype's middle display name in its locale.
public static String getMiddleDisplayName(InputMethodSubtype subtype) {
if (isNoLanguage(subtype)) {
return getKeyboardLayoutSetName(subtype).toUpperCase();
}
final Locale locale = getSubtypeLocale(subtype);
return StringUtils.toTitleCase(locale.getDisplayLanguage(locale), locale);
}
// Get InputMethodSubtype's short display name in its locale.
public static String getShortDisplayName(InputMethodSubtype subtype) {
if (isNoLanguage(subtype)) {
return "";
}
final Locale locale = getSubtypeLocale(subtype);
return StringUtils.toTitleCase(locale.getLanguage(), locale);
}
public static boolean isNoLanguage(InputMethodSubtype subtype) {
final String localeString = subtype.getLocale();
return localeString.equals(NO_LANGUAGE);
}
public static Locale getSubtypeLocale(InputMethodSubtype subtype) {
final String localeString = subtype.getLocale();
return LocaleUtils.constructLocaleFromString(localeString);
}
public static String getKeyboardLayoutSetName(InputMethodSubtype subtype) {
@ -117,22 +113,7 @@ public class SubtypeLocale {
LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET);
// TODO: Remove this null check when InputMethodManager.getCurrentInputMethodSubtype is
// fixed.
if (keyboardLayoutSet == null) return DEFAULT_KEYBOARD_LAYOUT_SET;
final int pos = keyboardLayoutSet.indexOf(KEYBOARD_LAYOUT_SET_LOCALE_DELIMITER);
return (pos > 0) ? keyboardLayoutSet.substring(0, pos) : keyboardLayoutSet;
}
public static String getKeyboardLayoutSetLocaleString(InputMethodSubtype subtype) {
final String keyboardLayoutSet = subtype.getExtraValueOf(
LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET);
// TODO: Remove this null check when InputMethodManager.getCurrentInputMethodSubtype is
// fixed.
if (keyboardLayoutSet == null) return subtype.getLocale();
final int pos = keyboardLayoutSet.indexOf(KEYBOARD_LAYOUT_SET_LOCALE_DELIMITER);
return (pos > 0) ? keyboardLayoutSet.substring(pos + 1) : subtype.getLocale();
}
public static Locale getKeyboardLayoutSetLocale(InputMethodSubtype subtype) {
return LocaleUtils.constructLocaleFromString(getKeyboardLayoutSetLocaleString(subtype));
if (keyboardLayoutSet == null) return AdditionalSubtype.QWERTY;
return keyboardLayoutSet;
}
}

View File

@ -105,7 +105,7 @@ public class SubtypeSwitcher {
mCurrentSubtype = mImm.getCurrentInputMethodSubtype();
mAllEnabledSubtypesOfCurrentInputMethod = null;
mNoLanguageSubtype = SubtypeUtils.findSubtypeByLocaleAndKeyboardLayoutSet(
service, SubtypeLocale.LOCALE_NO_LANGUAGE_QWERTY, "qwerty");
service, SubtypeLocale.LOCALE_NO_LANGUAGE, AdditionalSubtype.QWERTY);
final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
mIsNetworkConnected = (info != null && info.isConnected());
@ -135,7 +135,7 @@ public class SubtypeSwitcher {
mEnabledLanguagesOfCurrentInputMethod.clear();
mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
for (InputMethodSubtype ims : mAllEnabledSubtypesOfCurrentInputMethod) {
final String locale = SubtypeLocale.getKeyboardLayoutSetLocaleString(ims);
final String locale = ims.getLocale();
final String mode = ims.getMode();
mLocaleSplitter.setString(locale);
if (mLocaleSplitter.hasNext()) {
@ -165,8 +165,7 @@ public class SubtypeSwitcher {
+ (mShortcutInputMethodInfo == null
? "<null>" : mShortcutInputMethodInfo.getId()) + ", "
+ (mShortcutSubtype == null ? "<null>" : (
SubtypeLocale.getKeyboardLayoutSetLocaleString(mShortcutSubtype)
+ ", " + mShortcutSubtype.getMode())));
mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode())));
}
// TODO: Update an icon for shortcut IME
final Map<InputMethodInfo, List<InputMethodSubtype>> shortcuts =
@ -188,14 +187,13 @@ public class SubtypeSwitcher {
+ (mShortcutInputMethodInfo == null
? "<null>" : mShortcutInputMethodInfo.getId()) + ", "
+ (mShortcutSubtype == null ? "<null>" : (
SubtypeLocale.getKeyboardLayoutSetLocaleString(mShortcutSubtype)
+ ", " + mShortcutSubtype.getMode())));
mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode())));
}
}
// Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function.
public void updateSubtype(InputMethodSubtype newSubtype) {
final String newLocale = SubtypeLocale.getKeyboardLayoutSetLocaleString(newSubtype);
final String newLocale = newSubtype.getLocale();
final String newMode = newSubtype.getMode();
final String oldMode = mCurrentSubtype.getMode();
if (DBG) {
@ -335,7 +333,7 @@ public class SubtypeSwitcher {
}
public boolean needsToDisplayLanguage(Locale keyboardLocale) {
if (keyboardLocale.equals(SubtypeLocale.LOCALE_NO_LANGUAGE_QWERTY)) {
if (keyboardLocale.equals(SubtypeLocale.LOCALE_NO_LANGUAGE)) {
return true;
}
if (!keyboardLocale.equals(mInputLocale)) {

View File

@ -143,6 +143,7 @@ public class SubtypeUtils {
return subtype;
}
}
throw new RuntimeException("Can not find subtype of locale " + localeString);
throw new RuntimeException("Can't find subtype for locale " + localeString
+ " and keyboard layout " + keyoardLayoutSet);
}
}

View File

@ -18,56 +18,35 @@ package com.android.inputmethod.latin;
import android.content.Context;
import android.test.AndroidTestCase;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
import java.util.ArrayList;
import java.util.Locale;
public class SubtypeLocaleTests extends AndroidTestCase {
private static final Locale LOCALE_zz_QY = SubtypeLocale.LOCALE_NO_LANGUAGE_QWERTY;
private static final Locale LOCALE_de_QY =
new Locale(Locale.GERMAN.getLanguage(), SubtypeLocale.QWERTY);
private ArrayList<InputMethodSubtype> mSubtypesList;
// Locale to subtypes list.
private final ArrayList<InputMethodSubtype> mSubtypesList = new ArrayList<InputMethodSubtype>();
@Override
protected void setUp() throws Exception {
super.setUp();
final Context context = getContext();
final String packageName = context.getApplicationInfo().packageName;
InputMethodManagerCompatWrapper.init(context);
SubtypeLocale.init(context);
final InputMethodManager imm = (InputMethodManager) context.getSystemService(
Context.INPUT_METHOD_SERVICE);
for (final InputMethodInfo imi : imm.getInputMethodList()) {
if (imi.getPackageName().equals(packageName)) {
mSubtypesList = new ArrayList<InputMethodSubtype>();
final int subtypeCount = imi.getSubtypeCount();
for (int i = 0; i < subtypeCount; i++) {
final InputMethodSubtype ims = imi.getSubtypeAt(i);
mSubtypesList.add(ims);
}
break;
}
}
assertNotNull("Can not find input method " + packageName, mSubtypesList);
assertTrue("Can not find keyboard subtype", mSubtypesList.size() > 0);
}
public void testFullDisplayName() {
public void testAllFullDisplayName() {
final StringBuilder messages = new StringBuilder();
int failedCount = 0;
for (final InputMethodSubtype subtype : mSubtypesList) {
final Locale locale = SubtypeLocale.getKeyboardLayoutSetLocale(subtype);
if (locale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE)) {
final Locale locale = SubtypeLocale.getSubtypeLocale(subtype);
if (SubtypeLocale.isNoLanguage(subtype)) {
// This is special language name for language agnostic usage.
continue;
}
final String keyboardName = SubtypeLocale.getFullDisplayName(locale);
final String keyboardName = SubtypeLocale.getFullDisplayName(subtype);
final String languageName = StringUtils.toTitleCase(
locale.getDisplayLanguage(locale), locale);
if (!keyboardName.contains(languageName)) {
@ -80,24 +59,16 @@ public class SubtypeLocaleTests extends AndroidTestCase {
assertEquals(messages.toString(), 0, failedCount);
}
public void testFullDisplayNameNoLanguage() {
assertEquals("zz_QY", "QWERTY", SubtypeLocale.getFullDisplayName(LOCALE_zz_QY));
final String de_QY = SubtypeLocale.getFullDisplayName(LOCALE_de_QY);
assertTrue("de_QY", de_QY.contains("(QWERTY"));
assertTrue("de_QY", de_QY.contains(Locale.GERMAN.getDisplayLanguage(Locale.GERMAN)));
}
public void testMiddleDisplayName() {
public void testAllMiddleDisplayName() {
final StringBuilder messages = new StringBuilder();
int failedCount = 0;
for (final InputMethodSubtype subtype : mSubtypesList) {
final Locale locale = SubtypeLocale.getKeyboardLayoutSetLocale(subtype);
if (locale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE)) {
final Locale locale = SubtypeLocale.getSubtypeLocale(subtype);
if (SubtypeLocale.isNoLanguage(subtype)) {
// This is special language name for language agnostic usage.
continue;
}
final String keyboardName = SubtypeLocale.getMiddleDisplayName(locale);
final String keyboardName = SubtypeLocale.getMiddleDisplayName(subtype);
final String languageName = StringUtils.toTitleCase(
locale.getDisplayLanguage(locale), locale);
if (!keyboardName.equals(languageName)) {
@ -110,21 +81,12 @@ public class SubtypeLocaleTests extends AndroidTestCase {
assertEquals(messages.toString(), 0, failedCount);
}
public void testMiddleDisplayNameNoLanguage() {
assertEquals("zz_QY", "QWERTY", SubtypeLocale.getMiddleDisplayName(LOCALE_zz_QY));
assertEquals("de_QY", "Deutsch", SubtypeLocale.getMiddleDisplayName(LOCALE_de_QY));
}
public void testShortDisplayName() {
public void testAllShortDisplayName() {
final StringBuilder messages = new StringBuilder();
int failedCount = 0;
for (final InputMethodSubtype subtype : mSubtypesList) {
final Locale locale = SubtypeLocale.getKeyboardLayoutSetLocale(subtype);
if (locale.getCountry().equals(SubtypeLocale.QWERTY)) {
// This is special country code for QWERTY keyboard.
continue;
}
final String keyboardName = SubtypeLocale.getShortDisplayName(locale);
final Locale locale = SubtypeLocale.getSubtypeLocale(subtype);
final String keyboardName = SubtypeLocale.getShortDisplayName(subtype);
final String languageCode = StringUtils.toTitleCase(locale.getLanguage(), locale);
if (!keyboardName.equals(languageCode)) {
failedCount++;
@ -136,8 +98,99 @@ public class SubtypeLocaleTests extends AndroidTestCase {
assertEquals(messages.toString(), 0, failedCount);
}
public void testShortDisplayNameNoLanguage() {
assertEquals("zz_QY", "QY", SubtypeLocale.getShortDisplayName(LOCALE_zz_QY));
assertEquals("de_QY", "De", SubtypeLocale.getShortDisplayName(LOCALE_de_QY));
// Get InputMethodSubtype's display name in its locale.
// additional
// locale layout Short Middle Full
// ------ ------ - ---- --------- -----------------
// en_US qwerty F En English English (US) exception
// en_GB qwerty F En English English (UK) exception
// fr azerty F Fr Français Français
// fr_CA qwerty F Fr Français Français (Canada)
// de qwertz F De Deutsch Deutsch
// zz qwerty F QWERTY QWERTY
// fr qwertz T Fr Français Français (QWERTZ)
// de qwerty T De Deutsch Deutsch (QWERTY)
// zz azerty T AZERTY AZERTY
public void testSampleSubtypes() {
final Context context = getContext();
final InputMethodSubtype EN_US = SubtypeUtils.findSubtypeByLocaleAndKeyboardLayoutSet(
context, Locale.US, AdditionalSubtype.QWERTY);
final InputMethodSubtype EN_GB = SubtypeUtils.findSubtypeByLocaleAndKeyboardLayoutSet(
context, Locale.UK, AdditionalSubtype.QWERTY);
final InputMethodSubtype FR = SubtypeUtils.findSubtypeByLocaleAndKeyboardLayoutSet(
context, Locale.FRENCH, AdditionalSubtype.AZERTY);
final InputMethodSubtype FR_CA = SubtypeUtils.findSubtypeByLocaleAndKeyboardLayoutSet(
context, Locale.CANADA_FRENCH, AdditionalSubtype.QWERTY);
final InputMethodSubtype DE = SubtypeUtils.findSubtypeByLocaleAndKeyboardLayoutSet(
context, Locale.GERMAN, AdditionalSubtype.QWERTZ);
final InputMethodSubtype ZZ = SubtypeUtils.findSubtypeByLocaleAndKeyboardLayoutSet(
context, SubtypeLocale.LOCALE_NO_LANGUAGE, AdditionalSubtype.QWERTY);
assertFalse(AdditionalSubtype.isAdditionalSubtype(EN_US));
assertFalse(AdditionalSubtype.isAdditionalSubtype(EN_GB));
assertFalse(AdditionalSubtype.isAdditionalSubtype(FR));
assertFalse(AdditionalSubtype.isAdditionalSubtype(FR_CA));
assertFalse(AdditionalSubtype.isAdditionalSubtype(DE));
assertFalse(AdditionalSubtype.isAdditionalSubtype(ZZ));
assertEquals("en_US", "qwerty", SubtypeLocale.getKeyboardLayoutSetName(EN_US));
assertEquals("en_GB", "qwerty", SubtypeLocale.getKeyboardLayoutSetName(EN_GB));
assertEquals("fr ", "azerty", SubtypeLocale.getKeyboardLayoutSetName(FR));
assertEquals("fr_CA", "qwerty", SubtypeLocale.getKeyboardLayoutSetName(FR_CA));
assertEquals("de ", "qwertz", SubtypeLocale.getKeyboardLayoutSetName(DE));
assertEquals("zz ", "qwerty", SubtypeLocale.getKeyboardLayoutSetName(ZZ));
assertEquals("en_US", "English (US)", SubtypeLocale.getFullDisplayName(EN_US));
assertEquals("en_GB", "English (UK)", SubtypeLocale.getFullDisplayName(EN_GB));
assertEquals("fr ", "Français", SubtypeLocale.getFullDisplayName(FR));
assertEquals("fr_CA", "Français (Canada)", SubtypeLocale.getFullDisplayName(FR_CA));
assertEquals("de ", "Deutsch", SubtypeLocale.getFullDisplayName(DE));
assertEquals("zz ", "QWERTY", SubtypeLocale.getFullDisplayName(ZZ));
assertEquals("en_US", "English", SubtypeLocale.getMiddleDisplayName(EN_US));
assertEquals("en_GB", "English", SubtypeLocale.getMiddleDisplayName(EN_GB));
assertEquals("fr ", "Français", SubtypeLocale.getMiddleDisplayName(FR));
assertEquals("fr_CA", "Français", SubtypeLocale.getMiddleDisplayName(FR_CA));
assertEquals("de ", "Deutsch", SubtypeLocale.getMiddleDisplayName(DE));
assertEquals("zz ", "QWERTY", SubtypeLocale.getMiddleDisplayName(ZZ));
assertEquals("en_US", "En", SubtypeLocale.getShortDisplayName(EN_US));
assertEquals("en_GB", "En", SubtypeLocale.getShortDisplayName(EN_GB));
assertEquals("fr ", "Fr", SubtypeLocale.getShortDisplayName(FR));
assertEquals("fr_CA", "Fr", SubtypeLocale.getShortDisplayName(FR_CA));
assertEquals("de ", "De", SubtypeLocale.getShortDisplayName(DE));
assertEquals("zz ", "", SubtypeLocale.getShortDisplayName(ZZ));
}
public void testAdditionalSubtype() {
final InputMethodSubtype DE_QWERTY = AdditionalSubtype.createAddtionalSubtype(
Locale.GERMAN, AdditionalSubtype.QWERTY);
final InputMethodSubtype FR_QWERTZ = AdditionalSubtype.createAddtionalSubtype(
Locale.FRENCH, AdditionalSubtype.QWERTZ);
final InputMethodSubtype EN_AZERTY = AdditionalSubtype.createAddtionalSubtype(
Locale.ENGLISH, AdditionalSubtype.AZERTY);
final InputMethodSubtype ZZ_AZERTY = AdditionalSubtype.createAddtionalSubtype(
SubtypeLocale.LOCALE_NO_LANGUAGE, AdditionalSubtype.AZERTY);
assertTrue(AdditionalSubtype.isAdditionalSubtype(FR_QWERTZ));
assertTrue(AdditionalSubtype.isAdditionalSubtype(DE_QWERTY));
assertTrue(AdditionalSubtype.isAdditionalSubtype(EN_AZERTY));
assertTrue(AdditionalSubtype.isAdditionalSubtype(ZZ_AZERTY));
assertEquals("fr qwertz", "Français (QWERTZ)", SubtypeLocale.getFullDisplayName(FR_QWERTZ));
assertEquals("de qwerty", "Deutsch (QWERTY)", SubtypeLocale.getFullDisplayName(DE_QWERTY));
assertEquals("en azerty", "English (AZERTY)", SubtypeLocale.getFullDisplayName(EN_AZERTY));
assertEquals("zz azerty", "AZERTY", SubtypeLocale.getFullDisplayName(ZZ_AZERTY));
assertEquals("fr qwertz", "Français", SubtypeLocale.getMiddleDisplayName(FR_QWERTZ));
assertEquals("de qwerty", "Deutsch", SubtypeLocale.getMiddleDisplayName(DE_QWERTY));
assertEquals("en azerty", "English", SubtypeLocale.getMiddleDisplayName(EN_AZERTY));
assertEquals("zz azerty", "AZERTY", SubtypeLocale.getMiddleDisplayName(ZZ_AZERTY));
assertEquals("fr qwertz", "Fr", SubtypeLocale.getShortDisplayName(FR_QWERTZ));
assertEquals("de qwerty", "De", SubtypeLocale.getShortDisplayName(DE_QWERTY));
assertEquals("en azerty", "En", SubtypeLocale.getShortDisplayName(EN_AZERTY));
assertEquals("zz azerty", "", SubtypeLocale.getShortDisplayName(ZZ_AZERTY));
}
}