diff options
Diffstat (limited to 'java/src')
20 files changed, 432 insertions, 271 deletions
diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java index a1b49b475..b8655d112 100644 --- a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java +++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java @@ -43,6 +43,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Locale; +import java.util.Map.Entry; +import java.util.TreeMap; public class InputLanguageSelection extends PreferenceActivity { @@ -51,21 +53,17 @@ public class InputLanguageSelection extends PreferenceActivity { private HashMap<CheckBoxPreference, Locale> mLocaleMap = new HashMap<CheckBoxPreference, Locale>(); - private static class Loc implements Comparable<Object> { + private static class LocaleEntry implements Comparable<Object> { private static Collator sCollator = Collator.getInstance(); private String mLabel; public final Locale mLocale; - public Loc(String label, Locale locale) { + public LocaleEntry(String label, Locale locale) { this.mLabel = label; this.mLocale = locale; } - public void setLabel(String label) { - this.mLabel = label; - } - @Override public String toString() { return this.mLabel; @@ -73,7 +71,7 @@ public class InputLanguageSelection extends PreferenceActivity { @Override public int compareTo(Object o) { - return sCollator.compare(this.mLabel, ((Loc) o).mLabel); + return sCollator.compare(this.mLabel, ((LocaleEntry) o).mLabel); } } @@ -85,21 +83,58 @@ public class InputLanguageSelection extends PreferenceActivity { mPrefs = PreferenceManager.getDefaultSharedPreferences(this); mSelectedLanguages = mPrefs.getString(Settings.PREF_SELECTED_LANGUAGES, ""); String[] languageList = mSelectedLanguages.split(","); - ArrayList<Loc> availableLanguages = getUniqueLocales(); + ArrayList<LocaleEntry> availableLanguages = getUniqueLocales(); PreferenceGroup parent = getPreferenceScreen(); + final HashMap<Long, LocaleEntry> dictionaryIdLocaleMap = new HashMap<Long, LocaleEntry>(); + final TreeMap<LocaleEntry, Boolean> localeHasDictionaryMap = + new TreeMap<LocaleEntry, Boolean>(); for (int i = 0; i < availableLanguages.size(); i++) { - Locale locale = availableLanguages.get(i).mLocale; - final Pair<Boolean, Boolean> hasDictionaryOrLayout = hasDictionaryOrLayout(locale); - final boolean hasDictionary = hasDictionaryOrLayout.first; + LocaleEntry loc = availableLanguages.get(i); + Locale locale = loc.mLocale; + final Pair<Long, Boolean> hasDictionaryOrLayout = hasDictionaryOrLayout(locale); + final Long dictionaryId = hasDictionaryOrLayout.first; final boolean hasLayout = hasDictionaryOrLayout.second; + final boolean hasDictionary = dictionaryId != null; // Add this locale to the supported list if: - // 1) this locale has a layout/ 2) this locale has a dictionary and the length - // of the locale is equal to or larger than 5. - if (!hasLayout && !(hasDictionary && locale.toString().length() >= 5)) { + // 1) this locale has a layout/ 2) this locale has a dictionary + // If some locales have no layout but have a same dictionary, the shortest locale + // will be added to the supported list. + if (!hasLayout && !hasDictionary) { continue; } + if (hasLayout) { + localeHasDictionaryMap.put(loc, hasDictionary); + } + if (!hasDictionary) { + continue; + } + if (dictionaryIdLocaleMap.containsKey(dictionaryId)) { + final String newLocale = locale.toString(); + final String oldLocale = + dictionaryIdLocaleMap.get(dictionaryId).mLocale.toString(); + // Check if this locale is more appropriate to be the candidate of the input locale. + if (oldLocale.length() <= newLocale.length() && !hasLayout) { + // Don't add this new locale to the map<dictionary id, locale> if: + // 1) the new locale's name is longer than the existing one, and + // 2) the new locale doesn't have its layout + continue; + } + } + dictionaryIdLocaleMap.put(dictionaryId, loc); + } + + for (LocaleEntry localeEntry : dictionaryIdLocaleMap.values()) { + if (!localeHasDictionaryMap.containsKey(localeEntry)) { + localeHasDictionaryMap.put(localeEntry, true); + } + } + + for (Entry<LocaleEntry, Boolean> entry : localeHasDictionaryMap.entrySet()) { + final LocaleEntry localeEntry = entry.getKey(); + final Locale locale = localeEntry.mLocale; + final Boolean hasDictionary = entry.getValue(); CheckBoxPreference pref = new CheckBoxPreference(this); - pref.setTitle(SubtypeSwitcher.getFullDisplayName(locale, true)); + pref.setTitle(localeEntry.mLabel); boolean checked = isLocaleIn(locale, languageList); pref.setChecked(checked); if (hasDictionary) { @@ -118,11 +153,11 @@ public class InputLanguageSelection extends PreferenceActivity { return false; } - private Pair<Boolean, Boolean> hasDictionaryOrLayout(Locale locale) { - if (locale == null) return new Pair<Boolean, Boolean>(false, false); + private Pair<Long, Boolean> hasDictionaryOrLayout(Locale locale) { + if (locale == null) return new Pair<Long, Boolean>(null, false); final Resources res = getResources(); final Locale saveLocale = Utils.setSystemLocale(res, locale); - final boolean hasDictionary = DictionaryFactory.isDictionaryAvailable(this, locale); + final Long dictionaryId = DictionaryFactory.getDictionaryId(this, locale); boolean hasLayout = false; try { @@ -141,7 +176,7 @@ public class InputLanguageSelection extends PreferenceActivity { } catch (IOException e) { } Utils.setSystemLocale(res, saveLocale); - return new Pair<Boolean, Boolean>(hasDictionary, hasLayout); + return new Pair<Long, Boolean>(dictionaryId, hasLayout); } private String get5Code(Locale locale) { @@ -174,13 +209,13 @@ public class InputLanguageSelection extends PreferenceActivity { SharedPreferencesCompat.apply(editor); } - public ArrayList<Loc> getUniqueLocales() { + public ArrayList<LocaleEntry> getUniqueLocales() { String[] locales = getAssets().getLocales(); Arrays.sort(locales); - ArrayList<Loc> uniqueLocales = new ArrayList<Loc>(); + ArrayList<LocaleEntry> uniqueLocales = new ArrayList<LocaleEntry>(); final int origSize = locales.length; - Loc[] preprocess = new Loc[origSize]; + LocaleEntry[] preprocess = new LocaleEntry[origSize]; int finalSize = 0; for (int i = 0 ; i < origSize; i++ ) { String s = locales[i]; @@ -202,26 +237,13 @@ public class InputLanguageSelection extends PreferenceActivity { if (finalSize == 0) { preprocess[finalSize++] = - new Loc(SubtypeSwitcher.getFullDisplayName(l, true), l); + new LocaleEntry(SubtypeSwitcher.getFullDisplayName(l, false), l); } else { - // check previous entry: - // same lang and a country -> upgrade to full name and - // insert ours with full name - // diff lang -> insert ours with lang-only name - if (preprocess[finalSize-1].mLocale.getLanguage().equals( - language)) { - preprocess[finalSize-1].setLabel(SubtypeSwitcher.getFullDisplayName( - preprocess[finalSize-1].mLocale, false)); - preprocess[finalSize++] = - new Loc(SubtypeSwitcher.getFullDisplayName(l, false), l); + if (s.equals("zz_ZZ")) { + // ignore this locale } else { - String displayName; - if (s.equals("zz_ZZ")) { - // ignore this locale - } else { - displayName = SubtypeSwitcher.getFullDisplayName(l, true); - preprocess[finalSize++] = new Loc(displayName, l); - } + final String displayName = SubtypeSwitcher.getFullDisplayName(l, false); + preprocess[finalSize++] = new LocaleEntry(displayName, l); } } } diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java index 5ef236e31..8dc833d57 100644 --- a/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java +++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java @@ -20,6 +20,7 @@ import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.Settings; import com.android.inputmethod.latin.SharedPreferencesCompat; +import com.android.inputmethod.latin.Utils; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; @@ -125,8 +126,7 @@ public class LanguageSwitcher { private void constructLocales() { mLocales.clear(); for (final String lang : mSelectedLanguageArray) { - final Locale locale = new Locale(lang.substring(0, 2), - lang.length() > 4 ? lang.substring(3, 5) : ""); + final Locale locale = Utils.constructLocaleFromString(lang); mLocales.add(locale); } } diff --git a/java/src/com/android/inputmethod/latin/Recorrection.java b/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java index 3fa6292ba..bf69d5ced 100644 --- a/java/src/com/android/inputmethod/latin/Recorrection.java +++ b/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java @@ -14,11 +14,21 @@ * the License. */ -package com.android.inputmethod.latin; +package com.android.inputmethod.deprecated.recorrection; import com.android.inputmethod.compat.InputConnectionCompatUtils; import com.android.inputmethod.deprecated.VoiceProxy; import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.latin.AutoCorrection; +import com.android.inputmethod.latin.CandidateView; +import com.android.inputmethod.latin.EditingUtils; +import com.android.inputmethod.latin.LatinIME; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.Settings; +import com.android.inputmethod.latin.Suggest; +import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.TextEntryState; +import com.android.inputmethod.latin.WordComposer; import android.content.SharedPreferences; import android.content.res.Resources; @@ -32,12 +42,14 @@ import java.util.ArrayList; /** * Manager of re-correction functionalities */ -public class Recorrection { +public class Recorrection implements SharedPreferences.OnSharedPreferenceChangeListener { + public static final boolean USE_LEGACY_RECORRECTION = true; private static final Recorrection sInstance = new Recorrection(); private LatinIME mService; private boolean mRecorrectionEnabled = false; - private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>(); + private final ArrayList<RecorrectionSuggestionEntries> mRecorrectionSuggestionsList = + new ArrayList<RecorrectionSuggestionEntries>(); public static Recorrection getInstance() { return sInstance; @@ -58,20 +70,17 @@ public class Recorrection { } private void initInternal(LatinIME context, SharedPreferences prefs) { - final Resources res = context.getResources(); - // If the option should not be shown, do not read the re-correction preference - // but always use the default setting defined in the resources. - if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) { - mRecorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED, - res.getBoolean(R.bool.config_default_recorrection_enabled)); - } else { - mRecorrectionEnabled = res.getBoolean(R.bool.config_default_recorrection_enabled); + if (!USE_LEGACY_RECORRECTION) { + mRecorrectionEnabled = false; + return; } + updateRecorrectionEnabled(context.getResources(), prefs); mService = context; + prefs.registerOnSharedPreferenceChangeListener(this); } public void checkRecorrectionOnStart() { - if (!mRecorrectionEnabled) return; + if (!USE_LEGACY_RECORRECTION || !mRecorrectionEnabled) return; final InputConnection ic = mService.getCurrentInputConnection(); if (ic == null) return; @@ -98,42 +107,42 @@ public class Recorrection { } public void updateRecorrectionSelection(KeyboardSwitcher keyboardSwitcher, - CandidateView candidateView, int candidatesStart, int candidatesEnd, int newSelStart, - int newSelEnd, int oldSelStart, int lastSelectionStart, + CandidateView candidateView, int candidatesStart, int candidatesEnd, + int newSelStart, int newSelEnd, int oldSelStart, int lastSelectionStart, int lastSelectionEnd, boolean hasUncommittedTypedChars) { - if (mRecorrectionEnabled && mService.isShowingSuggestionsStrip()) { - // Don't look for corrections if the keyboard is not visible - if (keyboardSwitcher.isInputViewShown()) { - // Check if we should go in or out of correction mode. - if (mService.isSuggestionsRequested() - && (candidatesStart == candidatesEnd || newSelStart != oldSelStart - || TextEntryState.isRecorrecting()) - && (newSelStart < newSelEnd - 1 || !hasUncommittedTypedChars)) { - if (mService.isCursorTouchingWord() || lastSelectionStart < lastSelectionEnd) { - mService.mHandler.cancelUpdateBigramPredictions(); - mService.mHandler.postUpdateOldSuggestions(); - } else { - abortRecorrection(false); - // If showing the "touch again to save" hint, do not replace it. Else, - // show the bigrams if we are at the end of the text, punctuation otherwise. - if (candidateView != null - && !candidateView.isShowingAddToDictionaryHint()) { - InputConnection ic = mService.getCurrentInputConnection(); - if (null == ic || !TextUtils.isEmpty(ic.getTextAfterCursor(1, 0))) { - if (!mService.isShowingPunctuationList()) { - mService.setPunctuationSuggestions(); - } - } else { - mService.mHandler.postUpdateBigramPredictions(); - } + if (!USE_LEGACY_RECORRECTION || !mRecorrectionEnabled) return; + if (!mService.isShowingSuggestionsStrip()) return; + if (!keyboardSwitcher.isInputViewShown()) return; + if (!mService.isSuggestionsRequested()) return; + // Don't look for corrections if the keyboard is not visible + // Check if we should go in or out of correction mode. + if ((candidatesStart == candidatesEnd || newSelStart != oldSelStart || TextEntryState + .isRecorrecting()) + && (newSelStart < newSelEnd - 1 || !hasUncommittedTypedChars)) { + if (mService.isCursorTouchingWord() || lastSelectionStart < lastSelectionEnd) { + mService.mHandler.cancelUpdateBigramPredictions(); + mService.mHandler.postUpdateOldSuggestions(); + } else { + abortRecorrection(false); + // If showing the "touch again to save" hint, do not replace it. Else, + // show the bigrams if we are at the end of the text, punctuation + // otherwise. + if (candidateView != null && !candidateView.isShowingAddToDictionaryHint()) { + InputConnection ic = mService.getCurrentInputConnection(); + if (null == ic || !TextUtils.isEmpty(ic.getTextAfterCursor(1, 0))) { + if (!mService.isShowingPunctuationList()) { + mService.setPunctuationSuggestions(); } + } else { + mService.mHandler.postUpdateBigramPredictions(); } } } } } - public void saveWordInHistory(WordComposer word, CharSequence result) { + public void saveRecorrectionSuggestion(WordComposer word, CharSequence result) { + if (!USE_LEGACY_RECORRECTION || !mRecorrectionEnabled) return; if (word.size() <= 1) { return; } @@ -144,12 +153,13 @@ public class Recorrection { // Make a copy of the CharSequence, since it is/could be a mutable CharSequence final String resultCopy = result.toString(); - WordAlternatives entry = new WordAlternatives(resultCopy, new WordComposer(word)); - mWordHistory.add(entry); + RecorrectionSuggestionEntries entry = new RecorrectionSuggestionEntries( + resultCopy, new WordComposer(word)); + mRecorrectionSuggestionsList.add(entry); } public void clearWordsInHistory() { - mWordHistory.clear(); + mRecorrectionSuggestionsList.clear(); } /** @@ -160,11 +170,12 @@ public class Recorrection { */ public boolean applyTypedAlternatives(WordComposer word, Suggest suggest, KeyboardSwitcher keyboardSwitcher, EditingUtils.SelectedWord touching) { + if (!USE_LEGACY_RECORRECTION || !mRecorrectionEnabled) return false; // If we didn't find a match, search for result in typed word history WordComposer foundWord = null; - WordAlternatives alternatives = null; + RecorrectionSuggestionEntries alternatives = null; // Search old suggestions to suggest re-corrected suggestions. - for (WordAlternatives entry : mWordHistory) { + for (RecorrectionSuggestionEntries entry : mRecorrectionSuggestionsList) { if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) { foundWord = entry.mWordComposer; alternatives = entry; @@ -186,7 +197,7 @@ public class Recorrection { // Found a match, show suggestions if (foundWord != null || alternatives != null) { if (alternatives == null) { - alternatives = new WordAlternatives(touching.mWord, foundWord); + alternatives = new RecorrectionSuggestionEntries(touching.mWord, foundWord); } showRecorrections(suggest, keyboardSwitcher, alternatives); if (foundWord != null) { @@ -201,10 +212,10 @@ public class Recorrection { private void showRecorrections(Suggest suggest, KeyboardSwitcher keyboardSwitcher, - WordAlternatives alternatives) { - SuggestedWords.Builder builder = alternatives.getAlternatives(suggest, keyboardSwitcher); + RecorrectionSuggestionEntries entries) { + SuggestedWords.Builder builder = entries.getAlternatives(suggest, keyboardSwitcher); builder.setTypedWordValid(false).setHasMinimalSuggestion(false); - mService.showSuggestions(builder.build(), alternatives.getOriginalWord()); + mService.showSuggestions(builder.build(), entries.getOriginalWord()); } public void setRecorrectionSuggestions(VoiceProxy voiceProxy, CandidateView candidateView, @@ -212,6 +223,7 @@ public class Recorrection { boolean hasUncommittedTypedChars, int lastSelectionStart, int lastSelectionEnd, String wordSeparators) { if (!InputConnectionCompatUtils.RECORRECTION_SUPPORTED) return; + if (!USE_LEGACY_RECORRECTION || !mRecorrectionEnabled) return; voiceProxy.setShowingVoiceSuggestions(false); if (candidateView != null && candidateView.isShowingAddToDictionaryHint()) { return; @@ -245,6 +257,7 @@ public class Recorrection { } public void abortRecorrection(boolean force) { + if (!USE_LEGACY_RECORRECTION) return; if (force || TextEntryState.isRecorrecting()) { TextEntryState.onAbortRecorrection(); mService.setCandidatesViewShown(mService.isCandidateStripVisible()); @@ -252,4 +265,23 @@ public class Recorrection { mService.clearSuggestions(); } } + + public void updateRecorrectionEnabled(Resources res, SharedPreferences prefs) { + // If the option should not be shown, do not read the re-correction preference + // but always use the default setting defined in the resources. + if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) { + mRecorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED, + res.getBoolean(R.bool.config_default_recorrection_enabled)); + } else { + mRecorrectionEnabled = res.getBoolean(R.bool.config_default_recorrection_enabled); + } + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + if (!USE_LEGACY_RECORRECTION) return; + if (key.equals(Settings.PREF_RECORRECTION_ENABLED)) { + updateRecorrectionEnabled(mService.getResources(), prefs); + } + } } diff --git a/java/src/com/android/inputmethod/latin/WordAlternatives.java b/java/src/com/android/inputmethod/deprecated/recorrection/RecorrectionSuggestionEntries.java index 0e9914400..914e2cbc1 100644 --- a/java/src/com/android/inputmethod/latin/WordAlternatives.java +++ b/java/src/com/android/inputmethod/deprecated/recorrection/RecorrectionSuggestionEntries.java @@ -14,17 +14,20 @@ * the License. */ -package com.android.inputmethod.latin; +package com.android.inputmethod.deprecated.recorrection; import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.latin.Suggest; +import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.WordComposer; import android.text.TextUtils; -public class WordAlternatives { +public class RecorrectionSuggestionEntries { public final CharSequence mChosenWord; public final WordComposer mWordComposer; - public WordAlternatives(CharSequence chosenWord, WordComposer wordComposer) { + public RecorrectionSuggestionEntries(CharSequence chosenWord, WordComposer wordComposer) { mChosenWord = chosenWord; mWordComposer = wordComposer; } @@ -56,4 +59,4 @@ public class WordAlternatives { Suggest suggest, KeyboardSwitcher keyboardSwitcher, WordComposer word) { return suggest.getSuggestedWordBuilder(keyboardSwitcher.getInputView(), word, null); } -}
\ No newline at end of file +} diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index 5c59d4441..33b55b5d3 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -143,9 +143,9 @@ public class Key { * This constructor is being used only for key in mini popup keyboard. */ public Key(Resources res, Keyboard keyboard, CharSequence popupCharacter, int x, int y, - int width, int edgeFlags) { + int width, int height, int edgeFlags) { mKeyboard = keyboard; - mHeight = keyboard.getRowHeight() - keyboard.getVerticalGap(); + mHeight = height - keyboard.getVerticalGap(); mGap = keyboard.getHorizontalGap(); mVisualInsetsLeft = mVisualInsetsRight = 0; mWidth = width - mGap; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java index 69ae7886a..31fd0bfa3 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java @@ -196,9 +196,20 @@ public class KeyboardParser { final int keyboardHeight = (int)keyboardAttr.getDimension( R.styleable.Keyboard_keyboardHeight, displayHeight / 2); final int maxKeyboardHeight = getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2); - // Keyboard height will not exceed maxKeyboardHeight. - final int height = Math.min(keyboardHeight, maxKeyboardHeight); + R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2); + int minKeyboardHeight = getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_minKeyboardHeight, displayHeight, displayHeight / 2); + if (minKeyboardHeight < 0) { + // Specified fraction was negative, so it should be calculated against display + // width. + final int displayWidth = keyboard.getDisplayWidth(); + minKeyboardHeight = -getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2); + } + // Keyboard height will not exceed maxKeyboardHeight and will not be less than + // minKeyboardHeight. + final int height = Math.max( + Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight); final int width = keyboard.getDisplayWidth(); keyboard.setKeyboardHeight(height); diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 333fbc779..384139112 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -153,7 +153,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha final KeyboardId id = getKeyboardId(attribute, isSymbols); makeSymbolsKeyboardIds(id.mMode, attribute); mCurrentId = id; - mInputView.setKeyPreviewEnabled(mInputMethodService.getPopupOn()); + final Resources res = mInputMethodService.getResources(); + mInputView.setKeyPreviewPopupEnabled(Settings.Values.isKeyPreviewPopupEnabled(mPrefs, res), + Settings.Values.getKeyPreviewPopupDismissDelay(mPrefs, res)); setKeyboard(getKeyboard(id)); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index c551ed49f..4f85c0348 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -58,14 +58,22 @@ import java.util.WeakHashMap; * A view that renders a virtual {@link Keyboard}. It handles rendering of keys and detecting key * presses and touch movements. * + * @attr ref R.styleable#KeyboardView_backgroundDimAmount + * @attr ref R.styleable#KeyboardView_colorScheme * @attr ref R.styleable#KeyboardView_keyBackground + * @attr ref R.styleable#KeyboardView_keyHysteresisDistance + * @attr ref R.styleable#KeyboardView_keyLetterRatio + * @attr ref R.styleable#KeyboardView_keyLetterStyle * @attr ref R.styleable#KeyboardView_keyPreviewLayout * @attr ref R.styleable#KeyboardView_keyPreviewOffset - * @attr ref R.styleable#KeyboardView_labelTextSize - * @attr ref R.styleable#KeyboardView_keyTextSize + * @attr ref R.styleable#KeyboardView_keyPreviewHeight * @attr ref R.styleable#KeyboardView_keyTextColor + * @attr ref R.styleable#KeyboardView_keyTextColorDisabled + * @attr ref R.styleable#KeyboardView_labelTextRatio * @attr ref R.styleable#KeyboardView_verticalCorrection * @attr ref R.styleable#KeyboardView_popupLayout + * @attr ref R.styleable#KeyboardView_shadowColor + * @attr ref R.styleable#KeyboardView_shadowRadius */ public class KeyboardView extends View implements PointerTracker.UIProxy { private static final String TAG = KeyboardView.class.getSimpleName(); @@ -86,33 +94,36 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { private static final int HINT_ICON_VERTICAL_ADJUSTMENT_PIXEL = -1; // XML attribute - private int mKeyLetterSize; - private int mKeyTextColor; - private int mKeyTextColorDisabled; - private Typeface mKeyLetterStyle = Typeface.DEFAULT; - private int mLabelTextSize; - private int mColorScheme = COLOR_SCHEME_WHITE; - private int mShadowColor; - private float mShadowRadius; - private Drawable mKeyBackground; - private float mBackgroundDimAmount; - private float mKeyHysteresisDistance; - private float mVerticalCorrection; - private int mPreviewOffset; - private int mPreviewHeight; - private int mPopupLayout; + private final float mKeyLetterRatio; + private final int mKeyTextColor; + private final int mKeyTextColorDisabled; + private final Typeface mKeyLetterStyle; + private final float mLabelTextRatio; + private final int mColorScheme; + private final int mShadowColor; + private final float mShadowRadius; + private final Drawable mKeyBackground; + private final float mBackgroundDimAmount; + private final float mKeyHysteresisDistance; + private final float mVerticalCorrection; + private final int mPreviewOffset; + private final int mPreviewHeight; + private final int mPopupLayout; // Main keyboard private Keyboard mKeyboard; + private int mKeyLetterSize; + private int mLabelTextSize; // Key preview private boolean mInForeground; private TextView mPreviewText; - private int mPreviewTextSizeLarge; - private boolean mShowKeyPreview = true; - private int mKeyPreviewDisplayedY; + private float mPreviewTextRatio; + private int mPreviewTextSize; + private boolean mShowKeyPreviewPopup = true; + private int mKeyPreviewPopupDisplayedY; private final int mDelayBeforePreview; - private final int mDelayAfterPreview; + private int mDelayAfterPreview; private ViewGroup mPreviewPlacer; private final int[] mCoordinates = new int[2]; @@ -300,74 +311,36 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); - int previewLayout = 0; - int keyTextSize = 0; - int n = a.getIndexCount(); - - for (int i = 0; i < n; i++) { - int attr = a.getIndex(i); - - switch (attr) { - case R.styleable.KeyboardView_keyBackground: - mKeyBackground = a.getDrawable(attr); - break; - case R.styleable.KeyboardView_keyHysteresisDistance: - mKeyHysteresisDistance = a.getDimensionPixelOffset(attr, 0); - break; - case R.styleable.KeyboardView_verticalCorrection: - mVerticalCorrection = a.getDimensionPixelOffset(attr, 0); - break; - case R.styleable.KeyboardView_keyPreviewLayout: - previewLayout = a.getResourceId(attr, 0); - break; - case R.styleable.KeyboardView_keyPreviewOffset: - mPreviewOffset = a.getDimensionPixelOffset(attr, 0); - break; - case R.styleable.KeyboardView_keyPreviewHeight: - mPreviewHeight = a.getDimensionPixelSize(attr, 80); - break; - case R.styleable.KeyboardView_keyLetterSize: - mKeyLetterSize = a.getDimensionPixelSize(attr, 18); - break; - case R.styleable.KeyboardView_keyTextColor: - mKeyTextColor = a.getColor(attr, 0xFF000000); - break; - case R.styleable.KeyboardView_keyTextColorDisabled: - mKeyTextColorDisabled = a.getColor(attr, 0xFF000000); - break; - case R.styleable.KeyboardView_labelTextSize: - mLabelTextSize = a.getDimensionPixelSize(attr, 14); - break; - case R.styleable.KeyboardView_popupLayout: - mPopupLayout = a.getResourceId(attr, 0); - break; - case R.styleable.KeyboardView_shadowColor: - mShadowColor = a.getColor(attr, 0); - break; - case R.styleable.KeyboardView_shadowRadius: - mShadowRadius = a.getFloat(attr, 0f); - break; - // TODO: Use Theme (android.R.styleable.Theme_backgroundDimAmount) - case R.styleable.KeyboardView_backgroundDimAmount: - mBackgroundDimAmount = a.getFloat(attr, 0.5f); - break; - case R.styleable.KeyboardView_keyLetterStyle: - mKeyLetterStyle = Typeface.defaultFromStyle(a.getInt(attr, Typeface.NORMAL)); - break; - case R.styleable.KeyboardView_colorScheme: - mColorScheme = a.getInt(attr, COLOR_SCHEME_WHITE); - break; - } - } + mKeyBackground = a.getDrawable(R.styleable.KeyboardView_keyBackground); + mKeyHysteresisDistance = a.getDimensionPixelOffset( + R.styleable.KeyboardView_keyHysteresisDistance, 0); + mVerticalCorrection = a.getDimensionPixelOffset( + R.styleable.KeyboardView_verticalCorrection, 0); + final int previewLayout = a.getResourceId(R.styleable.KeyboardView_keyPreviewLayout, 0); + mPreviewOffset = a.getDimensionPixelOffset(R.styleable.KeyboardView_keyPreviewOffset, 0); + mPreviewHeight = a.getDimensionPixelSize(R.styleable.KeyboardView_keyPreviewHeight, 80); + mKeyLetterRatio = getRatio(a, R.styleable.KeyboardView_keyLetterRatio); + mKeyTextColor = a.getColor(R.styleable.KeyboardView_keyTextColor, 0xFF000000); + mKeyTextColorDisabled = a.getColor( + R.styleable.KeyboardView_keyTextColorDisabled, 0xFF000000); + mLabelTextRatio = getRatio(a, R.styleable.KeyboardView_labelTextRatio); + mPopupLayout = a.getResourceId(R.styleable.KeyboardView_popupLayout, 0); + mShadowColor = a.getColor(R.styleable.KeyboardView_shadowColor, 0); + mShadowRadius = a.getFloat(R.styleable.KeyboardView_shadowRadius, 0f); + // TODO: Use Theme (android.R.styleable.Theme_backgroundDimAmount) + mBackgroundDimAmount = a.getFloat(R.styleable.KeyboardView_backgroundDimAmount, 0.5f); + mKeyLetterStyle = Typeface.defaultFromStyle( + a.getInt(R.styleable.KeyboardView_keyLetterStyle, Typeface.NORMAL)); + mColorScheme = a.getInt(R.styleable.KeyboardView_colorScheme, COLOR_SCHEME_WHITE); final Resources res = getResources(); if (previewLayout != 0) { mPreviewText = (TextView) LayoutInflater.from(context).inflate(previewLayout, null); - mPreviewTextSizeLarge = (int) res.getDimension(R.dimen.key_preview_text_size_large); + mPreviewTextRatio = getRatio(res, R.fraction.key_preview_text_ratio); } else { - mShowKeyPreview = false; + mShowKeyPreviewPopup = false; } mDelayBeforePreview = res.getInteger(R.integer.config_delay_before_preview); mDelayAfterPreview = res.getInteger(R.integer.config_delay_after_preview); @@ -376,7 +349,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { mPaint = new Paint(); mPaint.setAntiAlias(true); - mPaint.setTextSize(keyTextSize); mPaint.setTextAlign(Align.CENTER); mPaint.setAlpha(255); @@ -460,6 +432,16 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval); } + // Read fraction value in TypedArray as float. + private static float getRatio(TypedArray a, int index) { + return a.getFraction(index, 1000, 1000, 1) / 1000.0f; + } + + // Read fraction value in resource as float. + private static float getRatio(Resources res, int id) { + return res.getFraction(id, 1000, 1000) / 1000.0f; + } + public void startIgnoringDoubleTap() { if (ENABLE_CAPSLOCK_BY_DOUBLETAP) mHandler.startIgnoringDoubleTap(); @@ -506,6 +488,10 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { invalidateAllKeys(); mKeyDetector.setProximityThreshold(keyboard.getMostCommonKeyWidth()); mPopupPanelCache.clear(); + final int keyHeight = keyboard.getRowHeight() - keyboard.getVerticalGap(); + mKeyLetterSize = (int)(keyHeight * mKeyLetterRatio); + mLabelTextSize = (int)(keyHeight * mLabelTextRatio); + mPreviewTextSize = (int)(keyHeight * mPreviewTextRatio); } /** @@ -530,19 +516,21 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { * Enables or disables the key feedback popup. This is a popup that shows a magnified * version of the depressed key. By default the preview is enabled. * @param previewEnabled whether or not to enable the key feedback preview - * @see #isKeyPreviewEnabled() + * @param delay the delay after which the preview is dismissed + * @see #isKeyPreviewPopupEnabled() */ - public void setKeyPreviewEnabled(boolean previewEnabled) { - mShowKeyPreview = previewEnabled; + public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) { + mShowKeyPreviewPopup = previewEnabled; + mDelayAfterPreview = delay; } /** * Returns the enabled state of the key feedback preview * @return whether or not the key feedback preview is enabled - * @see #setKeyPreviewEnabled(boolean) + * @see #setKeyPreviewPopupEnabled(boolean, int) */ - public boolean isKeyPreviewEnabled() { - return mShowKeyPreview; + public boolean isKeyPreviewPopupEnabled() { + return mShowKeyPreviewPopup; } public int getColorScheme() { @@ -865,7 +853,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { @Override public void showKeyPreview(int keyIndex, PointerTracker tracker) { - if (mShowKeyPreview) { + if (mShowKeyPreviewPopup) { mHandler.showKeyPreview(mDelayBeforePreview, keyIndex, tracker); } else if (mKeyboard.needSpacebarPreview(keyIndex)) { // Show key preview (in this case, slide language switcher) without any delay. @@ -875,7 +863,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { @Override public void dismissKeyPreview(PointerTracker tracker) { - if (mShowKeyPreview) { + if (mShowKeyPreviewPopup) { mHandler.cancelShowKeyPreview(tracker); mHandler.dismissKeyPreview(mDelayAfterPreview, tracker); } else if (mKeyboard.needSpacebarPreview(KeyDetector.NOT_A_KEY)) { @@ -938,7 +926,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyLetterSize); previewText.setTypeface(Typeface.DEFAULT_BOLD); } else { - previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mPreviewTextSizeLarge); + previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mPreviewTextSize); previewText.setTypeface(mKeyLetterStyle); } } else { @@ -960,7 +948,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { final int previewX = keyDrawX - (previewWidth - keyDrawWidth) / 2 + mCoordinates[0]; final int previewY = key.mY - previewHeight + mCoordinates[1] + mPreviewOffset; // Record key preview position to display mini-keyboard later at the same position - mKeyPreviewDisplayedY = previewY; + mKeyPreviewPopupDisplayedY = previewY; // Place the key preview. // TODO: Adjust position of key previews which touch screen edges @@ -1078,7 +1066,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { }); final Keyboard keyboard = new MiniKeyboardBuilder(this, mKeyboard.getPopupKeyboardResId(), - parentKey).build(); + parentKey, mKeyboard).build(); miniKeyboardView.setKeyboard(keyboard); container.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), @@ -1111,7 +1099,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { mPopupWindow.setClippingEnabled(false); } mPopupMiniKeyboardPanel = popupPanel; - popupPanel.showPanel(this, parentKey, tracker, mKeyPreviewDisplayedY, mPopupWindow); + popupPanel.showPanel(this, parentKey, tracker, mKeyPreviewPopupDisplayedY, mPopupWindow); invalidateAllKeys(); return true; diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java index c279769f6..7552b8ef0 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java @@ -78,7 +78,7 @@ public class LatinKeyboard extends Keyboard { // of the most common key width of this keyboard). private static final int SPACEBAR_DRAG_WIDTH = 3; // Minimum width of space key preview (proportional to keyboard width). - private static final float SPACEBAR_POPUP_MIN_RATIO = 0.4f; + private static final float SPACEBAR_POPUP_MIN_RATIO = 0.5f; // Height in space key the language name will be drawn. (proportional to space key height) public static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f; // If the full language name needs to be smaller than this value to be drawn on space key, diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index c98076f35..583b997ee 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -55,14 +55,14 @@ public class LatinKeyboardView extends KeyboardView { } @Override - public void setKeyPreviewEnabled(boolean previewEnabled) { + public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) { LatinKeyboard latinKeyboard = getLatinKeyboard(); if (latinKeyboard != null && (latinKeyboard.isPhoneKeyboard() || latinKeyboard.isNumberKeyboard())) { // Phone and number keyboard never shows popup preview (except language switch). - super.setKeyPreviewEnabled(false); + super.setKeyPreviewPopupEnabled(false, delay); } else { - super.setKeyPreviewEnabled(previewEnabled); + super.setKeyPreviewPopupEnabled(previewEnabled, delay); } } @@ -173,7 +173,8 @@ public class LatinKeyboardView extends KeyboardView { if (!mDroppingEvents) { mDroppingEvents = true; // Send an up event - MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), + MotionEvent translated = MotionEvent.obtain( + me.getEventTime(), me.getEventTime(), MotionEvent.ACTION_UP, mLastX, mLastY, me.getMetaState()); super.onTouchEvent(translated); diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java index e540fa106..2b83c3ff5 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java @@ -181,7 +181,8 @@ public class MiniKeyboardBuilder { } } - public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key parentKey) { + public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key parentKey, + Keyboard parentKeyboard) { final Context context = view.getContext(); mRes = context.getResources(); final MiniKeyboard keyboard = new MiniKeyboard(context, layoutTemplateResId, null); @@ -191,12 +192,13 @@ public class MiniKeyboardBuilder { final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, keyboard.getKeyWidth()); final MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( mPopupCharacters.length, parentKey.mMaxPopupColumn, - keyWidth, keyboard.getRowHeight(), + keyWidth, parentKeyboard.getRowHeight(), parentKey.mX + (parentKey.mWidth + parentKey.mGap) / 2 - keyWidth / 2, view.getMeasuredWidth()); mParams = params; - keyboard.setHeight(params.mNumRows * params.mRowHeight - keyboard.getVerticalGap()); + keyboard.setRowHeight(params.mRowHeight); + keyboard.setHeight(params.mNumRows * params.mRowHeight); keyboard.setMinWidth(params.mNumColumns * params.mKeyWidth); keyboard.setDefaultCoordX(params.getDefaultKeyCoordX() + params.mKeyWidth / 2); } @@ -235,7 +237,7 @@ public class MiniKeyboardBuilder { final CharSequence label = mPopupCharacters[n]; final int row = n / params.mNumColumns; final Key key = new Key(mRes, keyboard, label, params.getX(n, row), params.getY(row), - params.mKeyWidth, params.getRowFlags(row)); + params.mKeyWidth, params.mRowHeight, params.getRowFlags(row)); keys.add(key); } return keyboard; diff --git a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java index 12031f1ea..561dcbcef 100644 --- a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java @@ -55,13 +55,14 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { R.dimen.mini_keyboard_slide_allowance)); // Remove gesture detector on mini-keyboard mGestureDetector = null; - setKeyPreviewEnabled(false); + setKeyPreviewPopupEnabled(false, 0); } @Override - public void setKeyPreviewEnabled(boolean previewEnabled) { - // Mini keyboard needs no pop-up key preview displayed. - super.setKeyPreviewEnabled(false); + public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) { + // Mini keyboard needs no pop-up key preview displayed, so we pass always false with a + // delay of 0. The delay does not matter actually since the popup is not shown anyway. + super.setKeyPreviewPopupEnabled(false, 0); } @Override @@ -82,8 +83,8 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { - (container.getMeasuredHeight() - container.getPaddingBottom()) + parentKeyboardView.getPaddingTop() + mCoordinates[1]; final int x = miniKeyboardX; - final int y = parentKeyboardView.isKeyPreviewEnabled() && miniKeyboard.isOneRowKeyboard() - ? keyPreviewY : miniKeyboardY; + final int y = parentKeyboardView.isKeyPreviewPopupEnabled() && + miniKeyboard.isOneRowKeyboard() ? keyPreviewY : miniKeyboardY; if (miniKeyboard.setShifted(parentKeyboard.isShiftedOrShiftLocked())) { invalidateAllKeys(); diff --git a/java/src/com/android/inputmethod/keyboard/SlidingLocaleDrawable.java b/java/src/com/android/inputmethod/keyboard/SlidingLocaleDrawable.java index b279c1c7e..173e8790e 100644 --- a/java/src/com/android/inputmethod/keyboard/SlidingLocaleDrawable.java +++ b/java/src/com/android/inputmethod/keyboard/SlidingLocaleDrawable.java @@ -38,7 +38,7 @@ import android.view.ViewConfiguration; * movement on the spacebar. */ public class SlidingLocaleDrawable extends Drawable { - + private static final int SLIDE_SPEED_MULTIPLIER_RATIO = 150; private final Context mContext; private final Resources mRes; private final int mWidth; @@ -90,7 +90,7 @@ public class SlidingLocaleDrawable extends Drawable { mCurrentLanguage = null; return; } - mDiff = diff; + mDiff = Math.max(diff, diff * SLIDE_SPEED_MULTIPLIER_RATIO / 100); if (mDiff > mWidth) mDiff = mWidth; if (mDiff < -mWidth) mDiff = -mWidth; if (Math.abs(mDiff) > mThreshold) mHitThreshold = true; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index 562580d41..7ce92920d 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -78,16 +78,20 @@ class BinaryDictionaryGetter { } else { try { // If that was no-go, try to find a publicly exported dictionary. - return BinaryDictionaryFileDumper.getDictSetFromContentProvider(locale, context); + List<AssetFileAddress> listFromContentProvider = + BinaryDictionaryFileDumper.getDictSetFromContentProvider(locale, context); + if (null != listFromContentProvider) { + return listFromContentProvider; + } + // If the list is null, fall through and return the fallback } catch (FileNotFoundException e) { Log.e(TAG, "Unable to create dictionary file from provider for locale " + locale.toString() + ": falling back to internal dictionary"); - return Arrays.asList(loadFallbackResource(context, fallbackResId)); } catch (IOException e) { Log.e(TAG, "Unable to read source data for locale " + locale.toString() + ": falling back to internal dictionary"); - return Arrays.asList(loadFallbackResource(context, fallbackResId)); } + return Arrays.asList(loadFallbackResource(context, fallbackResId)); } } } diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index 605676d70..bba331868 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -142,6 +142,25 @@ public class DictionaryFactory { return hasDictionary; } + // TODO: Do not use the size of the dictionary as an unique dictionary ID. + public static Long getDictionaryId(Context context, Locale locale) { + final Resources res = context.getResources(); + final Locale saveLocale = Utils.setSystemLocale(res, locale); + + final int resourceId = Utils.getMainDictionaryResourceId(res); + final AssetFileDescriptor afd = res.openRawResourceFd(resourceId); + final Long size = (afd != null && afd.getLength() > PLACEHOLDER_LENGTH) + ? afd.getLength() + : null; + try { + if (null != afd) afd.close(); + } catch (java.io.IOException e) { + } + + Utils.setSystemLocale(res, saveLocale); + return size; + } + // TODO: Find the Right Way to find out whether the resource is a placeholder or not. // Suggestion : strip the locale, open the placeholder file and store its offset. // Upon opening the file, if it's the same offset, then it's the placeholder. diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 8b130aecd..18f743883 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -24,6 +24,7 @@ import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.deprecated.LanguageSwitcherProxy; import com.android.inputmethod.deprecated.VoiceProxy; +import com.android.inputmethod.deprecated.recorrection.Recorrection; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardActionListener; import com.android.inputmethod.keyboard.KeyboardSwitcher; @@ -405,7 +406,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void initSuggest() { final String localeStr = mSubtypeSwitcher.getInputLocaleStr(); - final Locale keyboardLocale = new Locale(localeStr); + final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr); final Resources res = mResources; final Locale savedLocale = Utils.setSystemLocale(res, keyboardLocale); @@ -439,7 +440,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /* package private */ void resetSuggestMainDict() { final String localeStr = mSubtypeSwitcher.getInputLocaleStr(); - final Locale keyboardLocale = new Locale(localeStr); + final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr); int mainDicResId = Utils.getMainDictionaryResourceId(mResources); mSuggest.resetMainDict(this, mainDicResId, keyboardLocale); } @@ -555,7 +556,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar updateCorrectionMode(); - inputView.setKeyPreviewEnabled(mSettingsValues.mPopupOn); + inputView.setKeyPreviewPopupEnabled(mSettingsValues.mKeyPreviewPopupOn, + mSettingsValues.mKeyPreviewPopupDismissDelay); inputView.setProximityCorrectionEnabled(true); // If we just entered a text field, maybe it has some old text that requires correction mRecorrection.checkRecorrectionOnStart(); @@ -684,7 +686,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // If the composing span has been cleared, save the typed word in the history for // recorrection before we reset the candidate strip. Then, we'll be able to show // suggestions for recorrection right away. - mRecorrection.saveWordInHistory(mWord, mComposing); + mRecorrection.saveRecorrectionSuggestion(mWord, mComposing); } mComposing.setLength(0); mHasUncommittedTypedChars = false; @@ -1221,7 +1223,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (!mHasUncommittedTypedChars) { mHasUncommittedTypedChars = true; mComposing.setLength(0); - mRecorrection.saveWordInHistory(mWord, mBestWord); + mRecorrection.saveRecorrectionSuggestion(mWord, mBestWord); mWord.reset(); clearSuggestions(); } @@ -1464,14 +1466,17 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // in most cases, suggestion count is 1 when typed word's length is 1, but we do always // need to clear the previous state when the user starts typing a word (i.e. typed word's // length == 1). - if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid - || mCandidateView.isShowingAddToDictionaryHint()) { - builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(correctionAvailable); - } else { - final SuggestedWords previousSuggestions = mCandidateView.getSuggestions(); - if (previousSuggestions == mSettingsValues.mSuggestPuncList) - return; - builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions); + if (typedWord != null) { + if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid + || mCandidateView.isShowingAddToDictionaryHint()) { + builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion( + correctionAvailable); + } else { + final SuggestedWords previousSuggestions = mCandidateView.getSuggestions(); + if (previousSuggestions == mSettingsValues.mSuggestPuncList) + return; + builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions); + } } showSuggestions(builder.build(), typedWord); } @@ -1548,7 +1553,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // a magic space even if it was a normal space. This is meant to help in case the user // pressed space on purpose of displaying the suggestion strip punctuation. final char primaryCode = suggestion.charAt(0); - final int toLeft = (ic == null) ? 0 : ic.getTextBeforeCursor(1, 0).charAt(0); + final CharSequence beforeText = ic != null ? ic.getTextBeforeCursor(1, 0) : ""; + final int toLeft = (ic == null || TextUtils.isEmpty(beforeText)) + ? 0 : beforeText.charAt(0); final boolean oldMagicSpace = mJustAddedMagicSpace; if (Keyboard.CODE_SPACE == toLeft) mJustAddedMagicSpace = true; onCodeInput(primaryCode, new int[] { primaryCode }, @@ -1602,8 +1609,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // TextEntryState.State.PICKED_SUGGESTION state. TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); - // From there on onUpdateSelection() will fire so suggestions will be updated - } else if (!showingAddToDictionaryHint) { + } + if (!showingAddToDictionaryHint) { // If we're not showing the "Touch again to save", then show corrections again. // In case the cursor position doesn't change, make sure we show the suggestions again. clearSuggestions(); @@ -1632,7 +1639,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mVoiceProxy.rememberReplacedWord(suggestion, mSettingsValues.mWordSeparators); ic.commitText(suggestion, 1); } - mRecorrection.saveWordInHistory(mWord, suggestion); + mRecorrection.saveRecorrectionSuggestion(mWord, suggestion); mHasUncommittedTypedChars = false; mCommittedLength = suggestion.length(); } @@ -1916,9 +1923,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return mWord; } - public boolean getPopupOn() { - return mSettingsValues.mPopupOn; - } boolean isSoundOn() { return mSettingsValues.mSoundOn && !mSilentModeOn; } @@ -2062,7 +2066,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar p.println(" TextEntryState.state=" + TextEntryState.getState()); p.println(" mSoundOn=" + mSettingsValues.mSoundOn); p.println(" mVibrateOn=" + mSettingsValues.mVibrateOn); - p.println(" mPopupOn=" + mSettingsValues.mPopupOn); + p.println(" mKeyPreviewPopupOn=" + mSettingsValues.mKeyPreviewPopupOn); } // Characters per second measurement diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 5eb365774..d64410a3d 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -56,7 +56,7 @@ public class Settings extends PreferenceActivity public static final String PREF_GENERAL_SETTINGS_KEY = "general_settings"; public static final String PREF_VIBRATE_ON = "vibrate_on"; public static final String PREF_SOUND_ON = "sound_on"; - public static final String PREF_POPUP_ON = "popup_on"; + public static final String PREF_KEY_PREVIEW_POPUP_ON = "popup_on"; public static final String PREF_RECORRECTION_ENABLED = "recorrection_enabled"; public static final String PREF_AUTO_CAP = "auto_cap"; public static final String PREF_SETTINGS_KEY = "settings_key"; @@ -77,6 +77,9 @@ public class Settings extends PreferenceActivity public static final String PREF_MISC_SETTINGS_KEY = "misc_settings"; + public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY = + "pref_key_preview_popup_dismiss_delay"; + public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; // Dialog ids @@ -102,7 +105,8 @@ public class Settings extends PreferenceActivity // From preferences: public final boolean mSoundOn; // Sound setting private to Latin IME (see mSilentModeOn) public final boolean mVibrateOn; - public final boolean mPopupOn; // Warning : this escapes through LatinIME#isPopupOn + public final boolean mKeyPreviewPopupOn; + public final int mKeyPreviewPopupDismissDelay; public final boolean mAutoCap; public final boolean mQuickFixes; public final boolean mAutoCorrectEnabled; @@ -117,7 +121,7 @@ public class Settings extends PreferenceActivity final Resources res = context.getResources(); final Locale savedLocale; if (null != localeStr) { - final Locale keyboardLocale = new Locale(localeStr); + final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr); savedLocale = Utils.setSystemLocale(res, keyboardLocale); } else { savedLocale = null; @@ -161,7 +165,8 @@ public class Settings extends PreferenceActivity mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, res.getBoolean(R.bool.config_default_sound_enabled)); - mPopupOn = isPopupEnabled(prefs, res); + mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res); + mKeyPreviewPopupDismissDelay = getKeyPreviewPopupDismissDelay(prefs, res); mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); mQuickFixes = isQuickFixesEnabled(prefs, res); @@ -172,6 +177,8 @@ public class Settings extends PreferenceActivity && isBigramPredictionEnabled(prefs, res); mAutoCorrectionThreshold = getAutoCorrectionThreshold(prefs, res); + + Utils.setSystemLocale(res, savedLocale); } public boolean isSuggestedPunctuation(int code) { @@ -200,6 +207,7 @@ public class Settings extends PreferenceActivity return sp.getBoolean(Settings.PREF_QUICK_FIXES, resources.getBoolean( R.bool.config_default_quick_fixes)); } + private static boolean isAutoCorrectEnabled(SharedPreferences sp, Resources resources) { final String currentAutoCorrectionSetting = sp.getString( Settings.PREF_AUTO_CORRECTION_THRESHOLD, @@ -208,13 +216,24 @@ public class Settings extends PreferenceActivity R.string.auto_correction_threshold_mode_index_off); return !currentAutoCorrectionSetting.equals(autoCorrectionOff); } - private static boolean isPopupEnabled(SharedPreferences sp, Resources resources) { + + // Public to access from KeyboardSwitcher. Should it have access to some + // process-global instance instead? + public static boolean isKeyPreviewPopupEnabled(SharedPreferences sp, Resources resources) { final boolean showPopupOption = resources.getBoolean( R.bool.config_enable_show_popup_on_keypress_option); if (!showPopupOption) return resources.getBoolean(R.bool.config_default_popup_preview); - return sp.getBoolean(Settings.PREF_POPUP_ON, + return sp.getBoolean(Settings.PREF_KEY_PREVIEW_POPUP_ON, resources.getBoolean(R.bool.config_default_popup_preview)); } + + // Likewise + public static int getKeyPreviewPopupDismissDelay(SharedPreferences sp, + Resources resources) { + return Integer.parseInt(sp.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, + Integer.toString(resources.getInteger(R.integer.config_delay_after_preview)))); + } + private static boolean isBigramSuggestionEnabled(SharedPreferences sp, Resources resources, boolean autoCorrectEnabled) { final boolean showBigramSuggestionsOption = resources.getBoolean( @@ -225,11 +244,13 @@ public class Settings extends PreferenceActivity return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, resources.getBoolean( R.bool.config_default_bigram_suggestions)); } + private static boolean isBigramPredictionEnabled(SharedPreferences sp, Resources resources) { return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, resources.getBoolean( R.bool.config_default_bigram_prediction)); } + private static double getAutoCorrectionThreshold(SharedPreferences sp, Resources resources) { final String currentAutoCorrectionSetting = sp.getString( @@ -255,6 +276,7 @@ public class Settings extends PreferenceActivity } return autoCorrectionThreshold; } + private static SuggestedWords createSuggestPuncList(final String puncs) { SuggestedWords.Builder builder = new SuggestedWords.Builder(); if (puncs != null) { @@ -272,6 +294,7 @@ public class Settings extends PreferenceActivity private ListPreference mSettingsKeyPreference; private ListPreference mShowCorrectionSuggestionsPreference; private ListPreference mAutoCorrectionThreshold; + private ListPreference mKeyPreviewPopupDismissDelay; // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary private CheckBoxPreference mBigramSuggestion; // Prediction: use bigrams to predict the next word when there is no input for it yet @@ -297,6 +320,8 @@ public class Settings extends PreferenceActivity @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); + final Resources res = getResources(); + addPreferencesFromResource(R.xml.prefs); mInputLanguageSelection = (PreferenceScreen) findPreference(PREF_SUBTYPES); mInputLanguageSelection.setOnPreferenceClickListener(this); @@ -329,16 +354,14 @@ public class Settings extends PreferenceActivity (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS_KEY); final PreferenceGroup textCorrectionGroup = (PreferenceGroup) findPreference(PREF_CORRECTION_SETTINGS_KEY); - final PreferenceGroup bigramGroup = - (PreferenceGroup) findPreference(PREF_NGRAM_SETTINGS_KEY); - final boolean showSettingsKeyOption = getResources().getBoolean( + final boolean showSettingsKeyOption = res.getBoolean( R.bool.config_enable_show_settings_key_option); if (!showSettingsKeyOption) { generalSettings.removePreference(mSettingsKeyPreference); } - final boolean showVoiceKeyOption = getResources().getBoolean( + final boolean showVoiceKeyOption = res.getBoolean( R.bool.config_enable_show_voice_key_option); if (!showVoiceKeyOption) { generalSettings.removePreference(mVoicePreference); @@ -348,43 +371,60 @@ public class Settings extends PreferenceActivity generalSettings.removePreference(findPreference(PREF_VIBRATE_ON)); } - final boolean showSubtypeSettings = getResources().getBoolean( + final boolean showSubtypeSettings = res.getBoolean( R.bool.config_enable_show_subtype_settings); if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED && !showSubtypeSettings) { generalSettings.removePreference(findPreference(PREF_SUBTYPES)); } - final boolean showPopupOption = getResources().getBoolean( + final boolean showPopupOption = res.getBoolean( R.bool.config_enable_show_popup_on_keypress_option); if (!showPopupOption) { - generalSettings.removePreference(findPreference(PREF_POPUP_ON)); + generalSettings.removePreference(findPreference(PREF_KEY_PREVIEW_POPUP_ON)); } - final boolean showRecorrectionOption = getResources().getBoolean( + final boolean showRecorrectionOption = res.getBoolean( R.bool.config_enable_show_recorrection_option); if (!showRecorrectionOption) { generalSettings.removePreference(findPreference(PREF_RECORRECTION_ENABLED)); } - final boolean showQuickFixesOption = getResources().getBoolean( + final boolean showQuickFixesOption = res.getBoolean( R.bool.config_enable_quick_fixes_option); if (!showQuickFixesOption) { textCorrectionGroup.removePreference(findPreference(PREF_QUICK_FIXES)); } - final boolean showBigramSuggestionsOption = getResources().getBoolean( + final boolean showBigramSuggestionsOption = res.getBoolean( R.bool.config_enable_bigram_suggestions_option); if (!showBigramSuggestionsOption) { textCorrectionGroup.removePreference(findPreference(PREF_BIGRAM_SUGGESTIONS)); textCorrectionGroup.removePreference(findPreference(PREF_BIGRAM_PREDICTIONS)); } - final boolean showUsabilityModeStudyOption = getResources().getBoolean( + final boolean showUsabilityModeStudyOption = res.getBoolean( R.bool.config_enable_usability_study_mode_option); if (!showUsabilityModeStudyOption) { getPreferenceScreen().removePreference(findPreference(PREF_USABILITY_STUDY_MODE)); } + + mKeyPreviewPopupDismissDelay = + (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); + final String[] entries = new String[] { + res.getString(R.string.key_preview_popup_dismiss_no_delay), + res.getString(R.string.key_preview_popup_dismiss_default_delay), + }; + final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger( + R.integer.config_delay_after_preview)); + mKeyPreviewPopupDismissDelay.setEntries(entries); + mKeyPreviewPopupDismissDelay.setEntryValues( + new String[] { "0", popupDismissDelayDefaultValue }); + if (null == mKeyPreviewPopupDismissDelay.getValue()) { + mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); + } + mKeyPreviewPopupDismissDelay.setEnabled( + Settings.Values.isKeyPreviewPopupEnabled(prefs, res)); } @Override @@ -403,6 +443,7 @@ public class Settings extends PreferenceActivity } updateSettingsKeySummary(); updateShowCorrectionSuggestionsSummary(); + updateKeyPreviewPopupDelaySummary(); } @Override @@ -421,6 +462,12 @@ public class Settings extends PreferenceActivity .equals(mVoiceModeOff)) { showVoiceConfirmation(); } + } else if (key.equals(PREF_KEY_PREVIEW_POPUP_ON)) { + final ListPreference popupDismissDelay = + (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); + if (null != popupDismissDelay) { + popupDismissDelay.setEnabled(prefs.getBoolean(PREF_KEY_PREVIEW_POPUP_ON, true)); + } } ensureConsistencyOfAutoCorrectionSettings(); mVoiceOn = !(prefs.getString(PREF_VOICE_SETTINGS_KEY, mVoiceModeOff) @@ -428,6 +475,7 @@ public class Settings extends PreferenceActivity updateVoiceModeSummary(); updateSettingsKeySummary(); updateShowCorrectionSuggestionsSummary(); + updateKeyPreviewPopupDelaySummary(); } @Override @@ -454,6 +502,11 @@ public class Settings extends PreferenceActivity [mSettingsKeyPreference.findIndexOfValue(mSettingsKeyPreference.getValue())]); } + private void updateKeyPreviewPopupDelaySummary() { + final ListPreference lp = mKeyPreviewPopupDismissDelay; + lp.setSummary(lp.getEntries()[lp.findIndexOfValue(lp.getValue())]); + } + private void showVoiceConfirmation() { mOkClicked = false; showDialog(VOICE_INPUT_CONFIRM_DIALOG); diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index d8012087b..50128430d 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -92,10 +92,9 @@ public class SubtypeSwitcher { } public static void init(LatinIME service, SharedPreferences prefs) { + SubtypeLocale.init(service); sInstance.initialize(service, prefs); sInstance.updateAllParameters(); - - SubtypeLocale.init(service); } private SubtypeSwitcher() { @@ -281,14 +280,8 @@ public class SubtypeSwitcher { // "en_US" --> language: en & country: US // "en" --> language: en // "" --> the system locale - mLocaleSplitter.setString(inputLocaleStr); - if (mLocaleSplitter.hasNext()) { - String language = mLocaleSplitter.next(); - if (mLocaleSplitter.hasNext()) { - mInputLocale = new Locale(language, mLocaleSplitter.next()); - } else { - mInputLocale = new Locale(language); - } + if (!TextUtils.isEmpty(inputLocaleStr)) { + mInputLocale = Utils.constructLocaleFromString(inputLocaleStr); mInputLocaleStr = inputLocaleStr; } else { mInputLocale = mSystemLocale; @@ -549,12 +542,12 @@ public class SubtypeSwitcher { || mEnabledKeyboardSubtypesOfCurrentInputMethod.size() == 0) return; mCurrentKeyboardSubtypeIndex = getCurrentIndex(); mNextKeyboardSubtype = getNextKeyboardSubtypeInternal(mCurrentKeyboardSubtypeIndex); - Locale locale = new Locale(mNextKeyboardSubtype.getLocale()); - mNextLanguage = getDisplayLanguage(locale); + Locale locale = Utils.constructLocaleFromString(mNextKeyboardSubtype.getLocale()); + mNextLanguage = getFullDisplayName(locale, true); mPreviousKeyboardSubtype = getPreviousKeyboardSubtypeInternal( mCurrentKeyboardSubtypeIndex); - locale = new Locale(mPreviousKeyboardSubtype.getLocale()); - mPreviousLanguage = getDisplayLanguage(locale); + locale = Utils.constructLocaleFromString(mPreviousKeyboardSubtype.getLocale()); + mPreviousLanguage = getFullDisplayName(locale, true); } private int normalize(int index) { @@ -591,11 +584,12 @@ public class SubtypeSwitcher { } public static String getDisplayLanguage(Locale locale) { - return toTitleCase(locale.getDisplayLanguage(locale)); + return toTitleCase(SubtypeLocale.getFullDisplayName(locale)); } public static String getMiddleDisplayLanguage(Locale locale) { - return toTitleCase((new Locale(locale.getLanguage()).getDisplayLanguage(locale))); + return toTitleCase((Utils.constructLocaleFromString( + locale.getLanguage()).getDisplayLanguage(locale))); } public static String getShortDisplayLanguage(Locale locale) { diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index d165de32d..5207f38ad 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -44,6 +44,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.HashMap; import java.util.Locale; public class Utils { @@ -662,4 +663,28 @@ public class Utils { res.updateConfiguration(conf, res.getDisplayMetrics()); return saveLocale; } + + private static final HashMap<String, Locale> sLocaleCache = new HashMap<String, Locale>(); + + public static Locale constructLocaleFromString(String localeStr) { + if (localeStr == null) + return null; + synchronized (sLocaleCache) { + if (sLocaleCache.containsKey(localeStr)) + return sLocaleCache.get(localeStr); + Locale retval = null; + String[] localeParams = localeStr.split("_", 3); + if (localeParams.length == 1) { + retval = new Locale(localeParams[0]); + } else if (localeParams.length == 2) { + retval = new Locale(localeParams[0], localeParams[1]); + } else if (localeParams.length == 3) { + retval = new Locale(localeParams[0], localeParams[1], localeParams[2]); + } + if (retval != null) { + sLocaleCache.put(localeStr, retval); + } + return retval; + } + } } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index cf0592920..af5e4b179 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -62,7 +62,7 @@ public class WordComposer { mYCoordinates = new int[N]; } - WordComposer(WordComposer source) { + public WordComposer(WordComposer source) { init(source); } |