diff options
Diffstat (limited to 'java/src')
8 files changed, 191 insertions, 33 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 811470c26..21477a992 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -280,7 +280,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha mSymbolsKeyboardId = getKeyboardId(editorInfo, true, false, settingsValues); mSymbolsShiftedKeyboardId = getKeyboardId(editorInfo, true, true, settingsValues); setKeyboard(getKeyboard(mSavedKeyboardState.getKeyboardId())); - updateShiftState(); } catch (RuntimeException e) { Log.w(TAG, "loading keyboard failed: " + mMainKeyboardId, e); LatinImeLogger.logOnException(mMainKeyboardId.toString(), e); @@ -331,6 +330,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha final boolean localeChanged = (oldKeyboard == null) || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale); mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged); + updateShiftState(); } private int getSwitchState(KeyboardId id) { @@ -543,11 +543,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } private void setAutomaticTemporaryUpperCase() { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) { - latinKeyboard.setAutomaticTemporaryUpperCase(); - mKeyboardView.invalidateAllKeys(); + if (mKeyboardView == null) return; + final Keyboard keyboard = mKeyboardView.getKeyboard(); + if (keyboard != null) { + keyboard.setAutomaticTemporaryUpperCase(); } + mKeyboardView.invalidateAllKeys(); } /** @@ -559,7 +560,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha Log.d(TAG, "updateShiftState:" + " autoCaps=" + mInputMethodService.getCurrentAutoCapsState() + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " shiftKeyState=" + shiftKeyState); + + " shiftKeyState=" + shiftKeyState + + " isAlphabetMode=" + isAlphabetMode() + + " isShiftLocked=" + isShiftLocked()); if (isAlphabetMode()) { if (!isShiftLocked() && !shiftKeyState.isIgnoring()) { if (shiftKeyState.isReleasing() && mInputMethodService.getCurrentAutoCapsState()) { diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 2df2994f6..bc021a690 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -83,6 +83,11 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { // HORIZONTAL ELLIPSIS "...", character for popup hint. private static final String POPUP_HINT_CHAR = "\u2026"; + // Margin between the label and the icon on a key that has both of them. + // Specified by the fraction of the key width. + // TODO: Use resource parameter for this value. + private static final float LABEL_ICON_MARGIN = 0.05f; + // Main keyboard private Keyboard mKeyboard; private final KeyDrawParams mKeyDrawParams; @@ -538,11 +543,13 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { positionX = centerX - labelCharWidth * 7 / 4; paint.setTextAlign(Align.LEFT); } else if (key.hasLabelWithIconLeft() && icon != null) { - labelWidth = getLabelWidth(label, paint) + icon.getIntrinsicWidth(); + labelWidth = getLabelWidth(label, paint) + icon.getIntrinsicWidth() + + (int)(LABEL_ICON_MARGIN * keyWidth); positionX = centerX + labelWidth / 2; paint.setTextAlign(Align.RIGHT); } else if (key.hasLabelWithIconRight() && icon != null) { - labelWidth = getLabelWidth(label, paint) + icon.getIntrinsicWidth(); + labelWidth = getLabelWidth(label, paint) + icon.getIntrinsicWidth() + + (int)(LABEL_ICON_MARGIN * keyWidth); positionX = centerX - labelWidth / 2; paint.setTextAlign(Align.LEFT); } else { @@ -734,7 +741,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { canvas.translate(-x, -y); } - private static void drawHorizontalLine(Canvas canvas, float y, float w, int color, Paint paint) { + private static void drawHorizontalLine(Canvas canvas, float y, float w, int color, + Paint paint) { paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(1.0f); paint.setColor(color); diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index 5e73d6300..7190b051d 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -56,12 +56,12 @@ public class ProximityInfo { computeNearestNeighbors(keyWidth, keys); } - public static ProximityInfo getDummyProximityInfo() { + public static ProximityInfo createDummyProximityInfo() { return new ProximityInfo(1, 1, 1, 1, 1, Collections.<Key>emptyList()); } - public static ProximityInfo getSpellCheckerProximityInfo() { - final ProximityInfo spellCheckerProximityInfo = getDummyProximityInfo(); + public static ProximityInfo createSpellCheckerProximityInfo() { + final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo(); spellCheckerProximityInfo.mNativeProximityInfo = spellCheckerProximityInfo.setProximityInfoNative( SpellCheckerProximityInfo.ROW_SIZE, diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java index de04ecd6c..f599def36 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java @@ -132,6 +132,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> { private int mCurrentY = 0; private Row mCurrentRow = null; private boolean mLeftEdge; + private boolean mTopEdge; private Key mRightEdgeKey = null; private final KeyStyles mKeyStyles = new KeyStyles(); @@ -650,6 +651,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> { private void startKeyboard() { mCurrentY += mParams.mTopPadding; + mTopEdge = true; } private void startRow(Row row) { @@ -670,6 +672,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> { setSpacer(mCurrentX, mParams.mHorizontalEdgesPadding); mCurrentY += mCurrentRow.mRowHeight; mCurrentRow = null; + mTopEdge = false; } private void endKey(Key key) { @@ -678,6 +681,9 @@ public class KeyboardBuilder<KP extends KeyboardParams> { key.addEdgeFlags(Keyboard.EDGE_LEFT); mLeftEdge = false; } + if (mTopEdge) { + key.addEdgeFlags(Keyboard.EDGE_TOP); + } mRightEdgeKey = key; } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java index 0cde4e5b5..fd98456a8 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java @@ -21,7 +21,7 @@ import android.util.Log; import com.android.inputmethod.keyboard.KeyboardSwitcher; public class KeyboardShiftState { - private static final String TAG = "KeyboardShiftState"; + private static final String TAG = KeyboardShiftState.class.getSimpleName(); private static final boolean DEBUG = KeyboardSwitcher.DEBUG_STATE; private static final int NORMAL = 0; diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 44e999572..649774d78 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -16,9 +16,11 @@ package com.android.inputmethod.latin.spellcheck; +import android.content.Intent; import android.content.res.Resources; import android.service.textservice.SpellCheckerService; import android.service.textservice.SpellCheckerService.Session; +import android.util.Log; import android.view.textservice.SuggestionsInfo; import android.view.textservice.TextInfo; @@ -34,8 +36,6 @@ import com.android.inputmethod.latin.WordComposer; import java.util.Arrays; import java.util.Collections; -import java.util.List; -import java.util.LinkedList; import java.util.Locale; import java.util.Map; import java.util.TreeMap; @@ -45,12 +45,12 @@ import java.util.TreeMap; */ public class AndroidSpellCheckerService extends SpellCheckerService { private static final String TAG = AndroidSpellCheckerService.class.getSimpleName(); - private static final boolean DBG = true; + private static final boolean DBG = false; + private static final int POOL_SIZE = 2; private final static String[] emptyArray = new String[0]; - private final ProximityInfo mProximityInfo = ProximityInfo.getSpellCheckerProximityInfo(); - private final Map<String, Dictionary> mDictionaries = - Collections.synchronizedMap(new TreeMap<String, Dictionary>()); + private Map<String, DictionaryPool> mDictionaryPools = + Collections.synchronizedMap(new TreeMap<String, DictionaryPool>()); @Override public Session createSession() { @@ -105,35 +105,53 @@ public class AndroidSpellCheckerService extends SpellCheckerService { } } - private Dictionary getDictionary(final String locale) { - Dictionary dictionary = mDictionaries.get(locale); - if (null == dictionary) { - final Resources resources = getResources(); - final int fallbackResourceId = Utils.getMainDictionaryResourceId(resources); + @Override + public boolean onUnbind(final Intent intent) { + final Map<String, DictionaryPool> oldPools = mDictionaryPools; + mDictionaryPools = Collections.synchronizedMap(new TreeMap<String, DictionaryPool>()); + for (DictionaryPool pool : oldPools.values()) { + pool.close(); + } + return false; + } + + private DictionaryPool getDictionaryPool(final String locale) { + DictionaryPool pool = mDictionaryPools.get(locale); + if (null == pool) { final Locale localeObject = Utils.constructLocaleFromString(locale); - dictionary = DictionaryFactory.createDictionaryFromManager(this, localeObject, - fallbackResourceId); - mDictionaries.put(locale, dictionary); + pool = new DictionaryPool(POOL_SIZE, this, localeObject); + mDictionaryPools.put(locale, pool); } - return dictionary; + return pool; + } + + public DictAndProximity createDictAndProximity(final Locale locale) { + final ProximityInfo proximityInfo = ProximityInfo.createSpellCheckerProximityInfo(); + final Resources resources = getResources(); + final int fallbackResourceId = Utils.getMainDictionaryResourceId(resources); + final Dictionary dictionary = + DictionaryFactory.createDictionaryFromManager(this, locale, fallbackResourceId); + return new DictAndProximity(dictionary, proximityInfo); } private class AndroidSpellCheckerSession extends Session { + // Immutable, but need the locale which is not available in the constructor yet + DictionaryPool mDictionaryPool; + @Override public void onCreate() { + mDictionaryPool = getDictionaryPool(getLocale()); } // Note : this must be reentrant /** * Gets a list of suggestions for a specific string. This returns a list of possible - * corrections for the text passed as an arguments. It may split or group words, and + * corrections for the text passed as an argument. It may split or group words, and * even perform grammatical analysis. */ @Override public SuggestionsInfo onGetSuggestions(final TextInfo textInfo, final int suggestionsLimit) { - final String locale = getLocale(); - final Dictionary dictionary = getDictionary(locale); final String text = textInfo.getText(); final SuggestionsGatherer suggestionsGatherer = @@ -153,8 +171,21 @@ public class AndroidSpellCheckerService extends SpellCheckerService { composer.add(character, proximities, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); } - dictionary.getWords(composer, suggestionsGatherer, mProximityInfo); - final boolean isInDict = dictionary.isValidWord(text); + + boolean isInDict = true; + try { + final DictAndProximity dictInfo = mDictionaryPool.take(); + dictInfo.mDictionary.getWords(composer, suggestionsGatherer, + dictInfo.mProximityInfo); + isInDict = dictInfo.mDictionary.isValidWord(text); + if (!mDictionaryPool.offer(dictInfo)) { + Log.e(TAG, "Can't re-insert a dictionary into its pool"); + } + } catch (InterruptedException e) { + // I don't think this can happen. + return new SuggestionsInfo(0, new String[0]); + } + final String[] suggestions = suggestionsGatherer.getGatheredSuggestions(); final int flags = diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java b/java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java new file mode 100644 index 000000000..3dbbd40cd --- /dev/null +++ b/java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 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.spellcheck; + +import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.keyboard.ProximityInfo; + +/** + * A simple container for both a Dictionary and a ProximityInfo. + */ +public class DictAndProximity { + public final Dictionary mDictionary; + public final ProximityInfo mProximityInfo; + public DictAndProximity(final Dictionary dictionary, final ProximityInfo proximityInfo) { + mDictionary = dictionary; + mProximityInfo = proximityInfo; + } +} diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java new file mode 100644 index 000000000..ee294f6b0 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 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.spellcheck; + +import android.content.Context; + +import java.util.Locale; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * A blocking queue that creates dictionaries up to a certain limit as necessary. + */ +public class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> { + private final AndroidSpellCheckerService mService; + private final int mMaxSize; + private final Locale mLocale; + private int mSize; + private volatile boolean mClosed; + + public DictionaryPool(final int maxSize, final AndroidSpellCheckerService service, + final Locale locale) { + super(); + mMaxSize = maxSize; + mService = service; + mLocale = locale; + mSize = 0; + mClosed = false; + } + + @Override + public DictAndProximity take() throws InterruptedException { + final DictAndProximity dict = poll(); + if (null != dict) return dict; + synchronized(this) { + if (mSize >= mMaxSize) { + // Our pool is already full. Wait until some dictionary is ready. + return super.take(); + } else { + ++mSize; + return mService.createDictAndProximity(mLocale); + } + } + } + + public void close() { + synchronized(this) { + mClosed = true; + for (DictAndProximity dict : this) { + dict.mDictionary.close(); + } + clear(); + } + } + + @Override + public boolean offer(final DictAndProximity dict) { + if (mClosed) { + dict.mDictionary.close(); + return false; + } else { + return super.offer(dict); + } + } +} |