Merge "Move KeyboardSwitcher.getKeyboard to KeyboardSet"

This commit is contained in:
Tadashi G. Takaoka 2011-12-16 03:13:38 -08:00 committed by Android (Google) Code Review
commit bf7ed75e4f
9 changed files with 135 additions and 120 deletions

View file

@ -60,8 +60,6 @@ public class KeyboardId {
public final int mOrientation;
public final int mWidth;
public final int mMode;
// TODO: Remove this field.
private final int mXmlId;
public final int mElementState;
private final int mInputType;
private final int mImeOptions;
@ -72,14 +70,13 @@ public class KeyboardId {
private final int mHashCode;
public KeyboardId(int xmlId, int elementState, Locale locale, int orientation, int width,
int mode, int inputType, int imeOptions, boolean settingsKeyEnabled,
boolean clobberSettingsKey, boolean shortcutKeyEnabled, boolean hasShortcutKey) {
public KeyboardId(int elementState, Locale locale, int orientation, int width, int mode,
int inputType, int imeOptions, boolean settingsKeyEnabled, boolean clobberSettingsKey,
boolean shortcutKeyEnabled, boolean hasShortcutKey) {
this.mLocale = locale;
this.mOrientation = orientation;
this.mWidth = width;
this.mMode = mode;
this.mXmlId = xmlId;
this.mElementState = elementState;
this.mInputType = inputType;
this.mImeOptions = imeOptions;
@ -97,7 +94,6 @@ public class KeyboardId {
id.mElementState,
id.mMode,
id.mWidth,
id.mXmlId,
id.navigateAction(),
id.passwordInput(),
id.mSettingsKeyEnabled,
@ -116,7 +112,6 @@ public class KeyboardId {
&& other.mElementState == this.mElementState
&& other.mMode == this.mMode
&& other.mWidth == this.mWidth
&& other.mXmlId == this.mXmlId
&& other.navigateAction() == this.navigateAction()
&& other.passwordInput() == this.passwordInput()
&& other.mSettingsKeyEnabled == this.mSettingsKeyEnabled
@ -127,16 +122,6 @@ public class KeyboardId {
&& other.mLocale.equals(this.mLocale);
}
public KeyboardId cloneWithNewXml(int xmlId) {
return new KeyboardId(xmlId, mElementState, mLocale, mOrientation, mWidth, mMode,
mInputType, mImeOptions, false, false, false, false);
}
// Remove this method.
public int getXmlId() {
return mXmlId;
}
public boolean isAlphabetKeyboard() {
return mElementState < ELEMENT_SYMBOLS;
}

View file

@ -20,11 +20,13 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.util.Log;
import android.util.Xml;
import android.view.inputmethod.EditorInfo;
import com.android.inputmethod.keyboard.internal.XmlParseUtils;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.LocaleUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SettingsValues;
@ -35,33 +37,29 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Locale;
/**
* This class has a set of {@link KeyboardId}s. Each of them represents a different keyboard
* specific to a keyboard state, such as alphabet, symbols, and so on. Layouts in the same
* {@link KeyboardSet} are related to each other. A {@link KeyboardSet} needs to be created for each
* {@link android.view.inputmethod.EditorInfo}.
* This class represents a set of keyboards. Each of them represents a different keyboard
* specific to a keyboard state, such as alphabet, symbols, and so on. Layouts in the same
* {@link KeyboardSet} are related to each other.
* A {@link KeyboardSet} needs to be created for each {@link android.view.inputmethod.EditorInfo}.
*/
public class KeyboardSet {
private static final String TAG_KEYBOARD_SET = "KeyboardSet";
private static final String TAG = KeyboardSet.class.getSimpleName();
private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG;
private static final String TAG_KEYBOARD_SET = TAG;
private static final String TAG_ELEMENT = "Element";
// TODO: Make these KeyboardId private.
public final KeyboardId mAlphabetId;
public final KeyboardId mSymbolsId;
public final KeyboardId mSymbolsShiftedId;
KeyboardSet(Params params) {
mAlphabetId = Builder.getKeyboardId(false, false, params);
mSymbolsId = Builder.getKeyboardId(true, false, params);
mSymbolsShiftedId = Builder.getKeyboardId(true, true, params);
}
private final Context mContext;
private final Params mParams;
private static class Params {
int mMode;
int mInputTypes;
int mInputType;
int mImeOptions;
boolean mSettingsKeyEnabled;
boolean mVoiceKeyEnabled;
@ -70,18 +68,94 @@ public class KeyboardSet {
Locale mLocale;
int mOrientation;
int mWidth;
final HashMap<Integer, Integer> mElementKeyboards =
new HashMap<Integer, Integer>();
final HashMap<Integer, Integer> mElementKeyboards = new HashMap<Integer, Integer>();
Params() {}
}
private static final HashMap<KeyboardId, SoftReference<LatinKeyboard>> sKeyboardCache =
new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
public static void clearKeyboardCache() {
sKeyboardCache.clear();
}
private KeyboardSet(Context context, Params params) {
mContext = context;
mParams = params;
}
public LatinKeyboard getMainKeyboard() {
return getKeyboard(false, false);
}
public LatinKeyboard getSymbolsKeyboard() {
return getKeyboard(true, false);
}
public LatinKeyboard getSymbolsShiftedKeyboard() {
final LatinKeyboard keyboard = getKeyboard(true, true);
// TODO: Remove this logic once we introduce initial keyboard shift state attribute.
// Symbol shift keyboard may have a shift key that has a caps lock style indicator (a.k.a.
// sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked()
// that takes care of the current keyboard having such shift key or not.
keyboard.setShiftLocked(keyboard.hasShiftLockKey());
return keyboard;
}
private LatinKeyboard getKeyboard(boolean isSymbols, boolean isShift) {
final int elementState = Builder.getElementState(mParams.mMode, isSymbols, isShift);
final int xmlId = mParams.mElementKeyboards.get(elementState);
final KeyboardId id = Builder.getKeyboardId(elementState, isSymbols, mParams);
final LatinKeyboard keyboard = getKeyboard(mContext, xmlId, id);
return keyboard;
}
public KeyboardId getMainKeyboardId() {
final int elementState = Builder.getElementState(mParams.mMode, false, false);
return Builder.getKeyboardId(elementState, false, mParams);
}
private static LatinKeyboard getKeyboard(Context context, int xmlId, KeyboardId id) {
final Resources res = context.getResources();
final SubtypeSwitcher subtypeSwitcher = SubtypeSwitcher.getInstance();
final SoftReference<LatinKeyboard> ref = sKeyboardCache.get(id);
LatinKeyboard keyboard = (ref == null) ? null : ref.get();
if (keyboard == null) {
final Locale savedLocale = LocaleUtils.setSystemLocale(res, id.mLocale);
try {
final LatinKeyboard.Builder builder = new LatinKeyboard.Builder(context);
builder.load(xmlId, id);
builder.setTouchPositionCorrectionEnabled(
subtypeSwitcher.currentSubtypeContainsExtraValueKey(
LatinIME.SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION));
keyboard = builder.build();
} finally {
LocaleUtils.setSystemLocale(res, savedLocale);
}
sKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard));
if (DEBUG_CACHE) {
Log.d(TAG, "keyboard cache size=" + sKeyboardCache.size() + ": "
+ ((ref == null) ? "LOAD" : "GCed") + " id=" + id);
}
} else if (DEBUG_CACHE) {
Log.d(TAG, "keyboard cache size=" + sKeyboardCache.size() + ": HIT id=" + id);
}
// TODO: Remove setShiftLocked and setShift calls.
keyboard.setShiftLocked(false);
keyboard.setShifted(false);
return keyboard;
}
public static class Builder {
private final Context mContext;
private final Resources mResources;
private final Params mParams = new Params();
public Builder(Context context, EditorInfo editorInfo, SettingsValues settingsValues) {
mContext = context;
mResources = context.getResources();
final SubtypeSwitcher subtypeSwitcher = SubtypeSwitcher.getInstance();
final String packageName = context.getPackageName();
@ -89,7 +163,7 @@ public class KeyboardSet {
params.mMode = Utils.getKeyboardMode(editorInfo);
if (editorInfo != null) {
params.mInputTypes = editorInfo.inputType;
params.mInputType = editorInfo.inputType;
params.mImeOptions = editorInfo.imeOptions;
}
params.mSettingsKeyEnabled = settingsValues.isSettingsKeyEnabled();
@ -121,21 +195,20 @@ public class KeyboardSet {
} finally {
LocaleUtils.setSystemLocale(mResources, savedLocale);
}
return new KeyboardSet(mParams);
return new KeyboardSet(mContext, mParams);
}
static KeyboardId getKeyboardId(boolean isSymbols, boolean isShift, Params params) {
final int elementState = getElementState(params.mMode, isSymbols, isShift);
final int xmlId = params.mElementKeyboards.get(elementState);
// TODO: Move this method to KeyboardSet
static KeyboardId getKeyboardId(int elementState, boolean isSymbols, Params params) {
final boolean hasShortcutKey = params.mVoiceKeyEnabled
&& (isSymbols != params.mVoiceKeyOnMain);
return new KeyboardId(xmlId, elementState, params.mLocale, params.mOrientation,
params.mWidth, params.mMode, params.mInputTypes, params.mImeOptions,
params.mSettingsKeyEnabled, params.mNoSettingsKey, params.mVoiceKeyEnabled,
hasShortcutKey);
return new KeyboardId(elementState, params.mLocale, params.mOrientation, params.mWidth,
params.mMode, params.mInputType, params.mImeOptions, params.mSettingsKeyEnabled,
params.mNoSettingsKey, params.mVoiceKeyEnabled, hasShortcutKey);
}
private static int getElementState(int mode, boolean isSymbols, boolean isShift) {
// TODO: Move this method to KeyboardSet
static int getElementState(int mode, boolean isSymbols, boolean isShift) {
switch (mode) {
case KeyboardId.MODE_PHONE:
return (isSymbols && isShift)

View file

@ -31,21 +31,15 @@ import com.android.inputmethod.keyboard.internal.KeyboardState;
import com.android.inputmethod.latin.InputView;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.LocaleUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.Settings;
import com.android.inputmethod.latin.SettingsValues;
import com.android.inputmethod.latin.SubtypeSwitcher;
import com.android.inputmethod.latin.Utils;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Locale;
public class KeyboardSwitcher implements KeyboardState.SwitchActions,
SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = KeyboardSwitcher.class.getSimpleName();
private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG;
public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20110916";
private static final int[] KEYBOARD_THEMES = {
@ -69,9 +63,6 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
private KeyboardSet mKeyboardSet;
private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
/** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of
* what user actually typed. */
private boolean mIsAutoCorrectionActive;
@ -121,25 +112,27 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
if (mThemeIndex != themeIndex) {
mThemeIndex = themeIndex;
mThemeContext = new ContextThemeWrapper(context, KEYBOARD_THEMES[themeIndex]);
mKeyboardCache.clear();
KeyboardSet.clearKeyboardCache();
}
}
public void loadKeyboard(EditorInfo editorInfo, SettingsValues settingsValues) {
mKeyboardSet = new KeyboardSet.Builder(mThemeContext, editorInfo, settingsValues)
.build();
final KeyboardId mainKeyboardId = mKeyboardSet.getMainKeyboardId();
try {
mKeyboardSet = new KeyboardSet.Builder(mInputMethodService, editorInfo, settingsValues)
.build();
mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols),
hasDistinctMultitouch());
// TODO: Should get rid of this special case handling for Phone Number layouts once we
// have separate layouts with unique KeyboardIds for alphabet and alphabet-shifted
// respectively.
if (mKeyboardSet.mAlphabetId.isPhoneKeyboard()) {
mState.onToggleAlphabetAndSymbols();
}
} catch (RuntimeException e) {
Log.w(TAG, "loading keyboard failed: " + mKeyboardSet.mAlphabetId, e);
LatinImeLogger.logOnException(mKeyboardSet.mAlphabetId.toString(), e);
Log.w(TAG, "loading keyboard failed: " + mainKeyboardId, e);
LatinImeLogger.logOnException(mainKeyboardId.toString(), e);
return;
}
// TODO: Should get rid of this special case handling for Phone Number layouts once we
// have separate layouts with unique KeyboardIds for alphabet and alphabet-shifted
// respectively.
if (mainKeyboardId.isPhoneKeyboard()) {
mState.onToggleAlphabetAndSymbols();
}
}
@ -181,39 +174,6 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
}
// TODO: Move this method to KeyboardSet.
private LatinKeyboard getKeyboard(Context context, KeyboardId id) {
final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id);
LatinKeyboard keyboard = (ref == null) ? null : ref.get();
if (keyboard == null) {
final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, id.mLocale);
try {
final LatinKeyboard.Builder builder = new LatinKeyboard.Builder(context);
builder.load(id);
builder.setTouchPositionCorrectionEnabled(
mSubtypeSwitcher.currentSubtypeContainsExtraValueKey(
LatinIME.SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION));
keyboard = builder.build();
} finally {
LocaleUtils.setSystemLocale(mResources, savedLocale);
}
mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard));
if (DEBUG_CACHE) {
Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": "
+ ((ref == null) ? "LOAD" : "GCed") + " id=" + id
+ " theme=" + themeName(keyboard.mThemeId));
}
} else if (DEBUG_CACHE) {
Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT id=" + id
+ " theme=" + themeName(keyboard.mThemeId));
}
keyboard.setShiftLocked(false);
keyboard.setShifted(false);
return keyboard;
}
public boolean isAlphabetMode() {
final Keyboard keyboard = getLatinKeyboard();
return keyboard != null && keyboard.mId.isAlphabetKeyboard();
@ -343,25 +303,19 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void setSymbolsKeyboard() {
setKeyboard(getKeyboard(mThemeContext, mKeyboardSet.mSymbolsId));
setKeyboard(mKeyboardSet.getMainKeyboard());
}
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void setAlphabetKeyboard() {
setKeyboard(getKeyboard(mThemeContext, mKeyboardSet.mAlphabetId));
setKeyboard(mKeyboardSet.getSymbolsKeyboard());
}
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void setSymbolsShiftedKeyboard() {
final Keyboard keyboard = getKeyboard(mThemeContext, mKeyboardSet.mSymbolsShiftedId);
setKeyboard(keyboard);
// TODO: Remove this logic once we introduce initial keyboard shift state attribute.
// Symbol shift keyboard may have a shift key that has a caps lock style indicator (a.k.a.
// sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked()
// that takes care of the current keyboard having such shift key or not.
keyboard.setShiftLocked(keyboard.hasShiftLockKey());
setKeyboard(mKeyboardSet.getSymbolsShiftedKeyboard());
}
public boolean isInMomentarySwitchState() {

View file

@ -109,6 +109,8 @@ public class LatinKeyboard extends Keyboard {
public Key mSpaceKey = null;
public Key mShortcutKey = null;
LatinKeyboardParams() {}
@Override
public void onAddKey(Key key) {
super.onAddKey(key);
@ -130,8 +132,8 @@ public class LatinKeyboard extends Keyboard {
}
@Override
public Builder load(KeyboardId id) {
super.load(id);
public Builder load(int xmlId, KeyboardId id) {
super.load(xmlId, id);
return this;
}

View file

@ -207,7 +207,7 @@ public class MiniKeyboard extends Keyboard {
public Builder(KeyboardView view, int xmlId, Key parentKey, Keyboard parentKeyboard) {
super(view.getContext(), new MiniKeyboardParams());
load(parentKeyboard.mId.cloneWithNewXml(xmlId));
load(xmlId, parentKeyboard.mId);
// TODO: Mini keyboard's vertical gap is currently calculated heuristically.
// Should revise the algorithm.

View file

@ -267,9 +267,9 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
params.mTouchPositionCorrection.load(data);
}
public KeyboardBuilder<KP> load(KeyboardId id) {
public KeyboardBuilder<KP> load(int xmlId, KeyboardId id) {
mParams.mId = id;
final XmlResourceParser parser = mResources.getXml(id.getXmlId());
final XmlResourceParser parser = mResources.getXml(xmlId);
try {
parseKeyboard(parser);
} catch (XmlPullParserException e) {

View file

@ -181,7 +181,7 @@ public class MoreSuggestions extends Keyboard {
int minWidth, int maxRow) {
final Keyboard keyboard = KeyboardSwitcher.getInstance().getLatinKeyboard();
final int xmlId = R.xml.kbd_suggestions_pane_template;
load(keyboard.mId.cloneWithNewXml(xmlId));
load(xmlId, keyboard.mId);
mParams.mVerticalGap = mParams.mTopPadding = keyboard.mVerticalGap / 2;
final int count = mParams.layout(suggestions, fromPos, maxWidth, minWidth, maxRow,

View file

@ -32,11 +32,13 @@ public class SuggestHelper {
protected final LatinKeyboard mKeyboard;
private final KeyDetector mKeyDetector;
public static final int ALPHABET_KEYBOARD = com.android.inputmethod.latin.R.xml.kbd_qwerty;
public SuggestHelper(Context context, int dictionaryId, KeyboardId keyboardId) {
// Use null as the locale for Suggest so as to force it to use the internal dictionary
// (and not try to find a dictionary provider for a specified locale)
mSuggest = new Suggest(context, dictionaryId, null);
mKeyboard = new LatinKeyboard.Builder(context).load(keyboardId).build();
mKeyboard = new LatinKeyboard.Builder(context).load(ALPHABET_KEYBOARD, keyboardId).build();
mKeyDetector = new KeyDetector(0);
init();
}
@ -45,7 +47,7 @@ public class SuggestHelper {
final long startOffset, final long length, final KeyboardId keyboardId,
final Locale locale) {
mSuggest = new Suggest(context, dictionaryPath, startOffset, length, null, locale);
mKeyboard = new LatinKeyboard.Builder(context).load(keyboardId).build();
mKeyboard = new LatinKeyboard.Builder(context).load(ALPHABET_KEYBOARD, keyboardId).build();
mKeyDetector = new KeyDetector(0);
init();
}

View file

@ -50,9 +50,8 @@ public class SuggestTestsBase extends AndroidTestCase {
+ "orientation=" + orientation);
return null;
}
return new KeyboardId(com.android.inputmethod.latin.R.xml.kbd_qwerty,
KeyboardId.ELEMENT_ALPHABET, locale, orientation, width, KeyboardId.MODE_TEXT,
InputType.TYPE_CLASS_TEXT, 0, false, false, false, false);
return new KeyboardId(KeyboardId.ELEMENT_ALPHABET, locale, orientation, width,
KeyboardId.MODE_TEXT, InputType.TYPE_CLASS_TEXT, 0, false, false, false, false);
}
protected InputStream openTestRawResource(int resIdInTest) {