diff options
Diffstat (limited to 'src')
33 files changed, 0 insertions, 8702 deletions
diff --git a/src/com/android/inputmethod/latin/AutoDictionary.java b/src/com/android/inputmethod/latin/AutoDictionary.java deleted file mode 100644 index 3d76dc301..000000000 --- a/src/com/android/inputmethod/latin/AutoDictionary.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import java.util.HashMap; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.database.sqlite.SQLiteQueryBuilder; -import android.provider.BaseColumns; -import android.provider.UserDictionary.Words; -import android.util.Log; - -/** - * Stores new words temporarily until they are promoted to the user dictionary - * for longevity. Words in the auto dictionary are used to determine if it's ok - * to accept a word that's not in the main or user dictionary. Using a new word - * repeatedly will promote it to the user dictionary. - */ -public class AutoDictionary extends ExpandableDictionary { - // Weight added to a user picking a new word from the suggestion strip - static final int FREQUENCY_FOR_PICKED = 3; - // Weight added to a user typing a new word that doesn't get corrected (or is reverted) - static final int FREQUENCY_FOR_TYPED = 1; - // A word that is frequently typed and gets promoted to the user dictionary, uses this - // frequency. - static final int FREQUENCY_FOR_AUTO_ADD = 250; - // If the user touches a typed word 2 times or more, it will become valid. - private static final int VALIDITY_THRESHOLD = 2 * FREQUENCY_FOR_PICKED; - // If the user touches a typed word 4 times or more, it will be added to the user dict. - private static final int PROMOTION_THRESHOLD = 4 * FREQUENCY_FOR_PICKED; - - private LatinIME mIme; - // Locale for which this auto dictionary is storing words - private String mLocale; - - private static final String DATABASE_NAME = "auto_dict.db"; - private static final int DATABASE_VERSION = 1; - - // These are the columns in the dictionary - // TODO: Consume less space by using a unique id for locale instead of the whole - // 2-5 character string. - private static final String COLUMN_ID = BaseColumns._ID; - private static final String COLUMN_WORD = "word"; - private static final String COLUMN_FREQUENCY = "freq"; - private static final String COLUMN_LOCALE = "locale"; - - /** Sort by descending order of frequency. */ - public static final String DEFAULT_SORT_ORDER = COLUMN_FREQUENCY + " DESC"; - - /** Name of the words table in the auto_dict.db */ - private static final String AUTODICT_TABLE_NAME = "words"; - - private static HashMap<String, String> sDictProjectionMap; - - static { - sDictProjectionMap = new HashMap<String, String>(); - sDictProjectionMap.put(COLUMN_ID, COLUMN_ID); - sDictProjectionMap.put(COLUMN_WORD, COLUMN_WORD); - sDictProjectionMap.put(COLUMN_FREQUENCY, COLUMN_FREQUENCY); - sDictProjectionMap.put(COLUMN_LOCALE, COLUMN_LOCALE); - } - - private DatabaseHelper mOpenHelper; - - public AutoDictionary(Context context, LatinIME ime, String locale) { - super(context); - mIme = ime; - mLocale = locale; - mOpenHelper = new DatabaseHelper(getContext()); - if (mLocale != null && mLocale.length() > 1) { - loadDictionary(); - } - } - - @Override - public boolean isValidWord(CharSequence word) { - final int frequency = getWordFrequency(word); - return frequency >= VALIDITY_THRESHOLD; - } - - public void close() { - mOpenHelper.close(); - } - - private void loadDictionary() { - // Load the words that correspond to the current input locale - Cursor cursor = query(COLUMN_LOCALE + "=?", new String[] { mLocale }); - if (cursor.moveToFirst()) { - int wordIndex = cursor.getColumnIndex(COLUMN_WORD); - int frequencyIndex = cursor.getColumnIndex(COLUMN_FREQUENCY); - while (!cursor.isAfterLast()) { - String word = cursor.getString(wordIndex); - int frequency = cursor.getInt(frequencyIndex); - // Safeguard against adding really long words. Stack may overflow due - // to recursive lookup - if (word.length() < getMaxWordLength()) { - super.addWord(word, frequency); - } - cursor.moveToNext(); - } - } - cursor.close(); - } - - @Override - public void addWord(String word, int addFrequency) { - final int length = word.length(); - // Don't add very short or very long words. - if (length < 2 || length > getMaxWordLength()) return; - if (mIme.getCurrentWord().isAutoCapitalized()) { - // Remove caps before adding - word = Character.toLowerCase(word.charAt(0)) + word.substring(1); - } - int freq = getWordFrequency(word); - freq = freq < 0 ? addFrequency : freq + addFrequency; - super.addWord(word, freq); - if (freq >= PROMOTION_THRESHOLD) { - mIme.promoteToUserDictionary(word, FREQUENCY_FOR_AUTO_ADD); - // Delete the word (for input locale) from the auto dictionary db, as it - // is now in the user dictionary provider. - delete(COLUMN_WORD + "=? AND " + COLUMN_LOCALE + "=?", - new String[] { word, mLocale }); - } else { - update(word, freq, mLocale); - } - } - - /** - * This class helps open, create, and upgrade the database file. - */ - private static class DatabaseHelper extends SQLiteOpenHelper { - - DatabaseHelper(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + AUTODICT_TABLE_NAME + " (" - + COLUMN_ID + " INTEGER PRIMARY KEY," - + COLUMN_WORD + " TEXT," - + COLUMN_FREQUENCY + " INTEGER," - + COLUMN_LOCALE + " TEXT" - + ");"); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - Log.w("AutoDictionary", "Upgrading database from version " + oldVersion + " to " - + newVersion + ", which will destroy all old data"); - db.execSQL("DROP TABLE IF EXISTS " + AUTODICT_TABLE_NAME); - onCreate(db); - } - } - - private Cursor query(String selection, String[] selectionArgs) { - SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); - qb.setTables(AUTODICT_TABLE_NAME); - qb.setProjectionMap(sDictProjectionMap); - - // Get the database and run the query - SQLiteDatabase db = mOpenHelper.getReadableDatabase(); - Cursor c = qb.query(db, null, selection, selectionArgs, null, null, - DEFAULT_SORT_ORDER); - return c; - } - - private boolean insert(ContentValues values) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - long rowId = db.insert(AUTODICT_TABLE_NAME, Words.WORD, values); - if (rowId > 0) { - return true; - } - return false; - } - - private int delete(String where, String[] whereArgs) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - int count = db.delete(AUTODICT_TABLE_NAME, where, whereArgs); - return count; - } - - private int update(String word, int frequency, String locale) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - long count = db.delete(AUTODICT_TABLE_NAME, COLUMN_WORD + "=? AND " + COLUMN_LOCALE + "=?", - new String[] { word, locale }); - count = db.insert(AUTODICT_TABLE_NAME, null, - getContentValues(word, frequency, locale)); - return (int) count; - } - - private ContentValues getContentValues(String word, int frequency, String locale) { - ContentValues values = new ContentValues(4); - values.put(COLUMN_WORD, word); - values.put(COLUMN_FREQUENCY, frequency); - values.put(COLUMN_LOCALE, locale); - return values; - } -} diff --git a/src/com/android/inputmethod/latin/BinaryDictionary.java b/src/com/android/inputmethod/latin/BinaryDictionary.java deleted file mode 100644 index 43f4c4cb6..000000000 --- a/src/com/android/inputmethod/latin/BinaryDictionary.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import java.util.Arrays; - -import android.content.Context; -import android.content.res.AssetManager; -import android.util.Log; - -/** - * Implements a static, compacted, binary dictionary of standard words. - */ -public class BinaryDictionary extends Dictionary { - - public static final int MAX_WORD_LENGTH = 48; - private static final int MAX_ALTERNATIVES = 16; - private static final int MAX_WORDS = 16; - - private static final int TYPED_LETTER_MULTIPLIER = 2; - private static final boolean ENABLE_MISSED_CHARACTERS = true; - - private int mNativeDict; - private int mDictLength; // This value is set from native code, don't change the name!!!! - private int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_ALTERNATIVES]; - private char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS]; - private int[] mFrequencies = new int[MAX_WORDS]; - - static { - try { - System.loadLibrary("jni_latinime"); - } catch (UnsatisfiedLinkError ule) { - Log.e("BinaryDictionary", "Could not load native library jni_latinime"); - } - } - - /** - * Create a dictionary from a raw resource file - * @param context application context for reading resources - * @param resId the resource containing the raw binary dictionary - */ - public BinaryDictionary(Context context, int resId) { - if (resId != 0) { - loadDictionary(context, resId); - } - } - - private native int openNative(AssetManager am, String resourcePath, int typedLetterMultiplier, - int fullWordMultiplier); - private native void closeNative(int dict); - private native boolean isValidWordNative(int nativeData, char[] word, int wordLength); - private native int getSuggestionsNative(int dict, int[] inputCodes, int codesSize, - char[] outputChars, int[] frequencies, - int maxWordLength, int maxWords, int maxAlternatives, int skipPos, - int[] nextLettersFrequencies, int nextLettersSize); - - private final void loadDictionary(Context context, int resId) { - AssetManager am = context.getResources().getAssets(); - String assetName = context.getResources().getString(resId); - mNativeDict = openNative(am, assetName, TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER); - } - - @Override - public void getWords(final WordComposer codes, final WordCallback callback, - int[] nextLettersFrequencies) { - final int codesSize = codes.size(); - // Wont deal with really long words. - if (codesSize > MAX_WORD_LENGTH - 1) return; - - Arrays.fill(mInputCodes, -1); - for (int i = 0; i < codesSize; i++) { - int[] alternatives = codes.getCodesAt(i); - System.arraycopy(alternatives, 0, mInputCodes, i * MAX_ALTERNATIVES, - Math.min(alternatives.length, MAX_ALTERNATIVES)); - } - Arrays.fill(mOutputChars, (char) 0); - Arrays.fill(mFrequencies, 0); - - int count = getSuggestionsNative(mNativeDict, mInputCodes, codesSize, - mOutputChars, mFrequencies, - MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES, -1, - nextLettersFrequencies, - nextLettersFrequencies != null ? nextLettersFrequencies.length : 0); - - // If there aren't sufficient suggestions, search for words by allowing wild cards at - // the different character positions. This feature is not ready for prime-time as we need - // to figure out the best ranking for such words compared to proximity corrections and - // completions. - if (ENABLE_MISSED_CHARACTERS && count < 5) { - for (int skip = 0; skip < codesSize; skip++) { - int tempCount = getSuggestionsNative(mNativeDict, mInputCodes, codesSize, - mOutputChars, mFrequencies, - MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES, skip, - null, 0); - count = Math.max(count, tempCount); - if (tempCount > 0) break; - } - } - - for (int j = 0; j < count; j++) { - if (mFrequencies[j] < 1) break; - int start = j * MAX_WORD_LENGTH; - int len = 0; - while (mOutputChars[start + len] != 0) { - len++; - } - if (len > 0) { - callback.addWord(mOutputChars, start, len, mFrequencies[j]); - } - } - } - - @Override - public boolean isValidWord(CharSequence word) { - if (word == null) return false; - char[] chars = word.toString().toCharArray(); - return isValidWordNative(mNativeDict, chars, chars.length); - } - - public int getSize() { - return mDictLength; // This value is initialized on the call to openNative() - } - - @Override - public synchronized void close() { - if (mNativeDict != 0) { - closeNative(mNativeDict); - mNativeDict = 0; - } - } - - @Override - protected void finalize() throws Throwable { - close(); - super.finalize(); - } -} diff --git a/src/com/android/inputmethod/latin/CandidateView.java b/src/com/android/inputmethod/latin/CandidateView.java deleted file mode 100755 index 0c0373b3b..000000000 --- a/src/com/android/inputmethod/latin/CandidateView.java +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.Typeface; -import android.graphics.Paint.Align; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.Message; -import android.util.AttributeSet; -import android.view.GestureDetector; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.widget.PopupWindow; -import android.widget.TextView; - -public class CandidateView extends View { - - private static final int OUT_OF_BOUNDS = -1; - private static final List<CharSequence> EMPTY_LIST = new ArrayList<CharSequence>(); - - private LatinIME mService; - private List<CharSequence> mSuggestions = EMPTY_LIST; - private boolean mShowingCompletions; - private CharSequence mSelectedString; - private int mSelectedIndex; - private int mTouchX = OUT_OF_BOUNDS; - private Drawable mSelectionHighlight; - private boolean mTypedWordValid; - - private boolean mHaveMinimalSuggestion; - - private Rect mBgPadding; - - private TextView mPreviewText; - private PopupWindow mPreviewPopup; - private int mCurrentWordIndex; - private Drawable mDivider; - - private static final int MAX_SUGGESTIONS = 32; - private static final int SCROLL_PIXELS = 20; - - private static final int MSG_REMOVE_PREVIEW = 1; - private static final int MSG_REMOVE_THROUGH_PREVIEW = 2; - - private int[] mWordWidth = new int[MAX_SUGGESTIONS]; - private int[] mWordX = new int[MAX_SUGGESTIONS]; - private int mPopupPreviewX; - private int mPopupPreviewY; - - private static final int X_GAP = 10; - - private int mColorNormal; - private int mColorRecommended; - private int mColorOther; - private Paint mPaint; - private int mDescent; - private boolean mScrolled; - private boolean mShowingAddToDictionary; - private CharSequence mWordToAddToDictionary; - private CharSequence mAddToDictionaryHint; - - private int mTargetScrollX; - - private int mMinTouchableWidth; - - private int mTotalWidth; - - private GestureDetector mGestureDetector; - - Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_REMOVE_PREVIEW: - mPreviewText.setVisibility(GONE); - break; - case MSG_REMOVE_THROUGH_PREVIEW: - mPreviewText.setVisibility(GONE); - if (mTouchX != OUT_OF_BOUNDS) { - removeHighlight(); - } - break; - } - - } - }; - - /** - * Construct a CandidateView for showing suggested words for completion. - * @param context - * @param attrs - */ - public CandidateView(Context context, AttributeSet attrs) { - super(context, attrs); - mSelectionHighlight = context.getResources().getDrawable( - R.drawable.list_selector_background_pressed); - - LayoutInflater inflate = - (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - Resources res = context.getResources(); - mPreviewPopup = new PopupWindow(context); - mPreviewText = (TextView) inflate.inflate(R.layout.candidate_preview, null); - mPreviewPopup.setWindowLayoutMode(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - mPreviewPopup.setContentView(mPreviewText); - mPreviewPopup.setBackgroundDrawable(null); - mColorNormal = res.getColor(R.color.candidate_normal); - mColorRecommended = res.getColor(R.color.candidate_recommended); - mColorOther = res.getColor(R.color.candidate_other); - mDivider = res.getDrawable(R.drawable.keyboard_suggest_strip_divider); - mAddToDictionaryHint = res.getString(R.string.hint_add_to_dictionary); - - mPaint = new Paint(); - mPaint.setColor(mColorNormal); - mPaint.setAntiAlias(true); - mPaint.setTextSize(mPreviewText.getTextSize()); - mPaint.setStrokeWidth(0); - mPaint.setTextAlign(Align.CENTER); - mDescent = (int) mPaint.descent(); - // 80 pixels for a 160dpi device would mean half an inch - mMinTouchableWidth = (int) (getResources().getDisplayMetrics().density * 50); - - mGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() { - @Override - public void onLongPress(MotionEvent me) { - if (mSuggestions.size() > 0) { - if (me.getX() + getScrollX() < mWordWidth[0] && getScrollX() < 10) { - longPressFirstWord(); - } - } - } - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, - float distanceX, float distanceY) { - final int width = getWidth(); - mScrolled = true; - int scrollX = getScrollX(); - scrollX += (int) distanceX; - if (scrollX < 0) { - scrollX = 0; - } - if (distanceX > 0 && scrollX + width > mTotalWidth) { - scrollX -= (int) distanceX; - } - mTargetScrollX = scrollX; - scrollTo(scrollX, getScrollY()); - hidePreview(); - invalidate(); - return true; - } - }); - setHorizontalFadingEdgeEnabled(true); - setWillNotDraw(false); - setHorizontalScrollBarEnabled(false); - setVerticalScrollBarEnabled(false); - scrollTo(0, getScrollY()); - } - - /** - * A connection back to the service to communicate with the text field - * @param listener - */ - public void setService(LatinIME listener) { - mService = listener; - } - - @Override - public int computeHorizontalScrollRange() { - return mTotalWidth; - } - - /** - * If the canvas is null, then only touch calculations are performed to pick the target - * candidate. - */ - @Override - protected void onDraw(Canvas canvas) { - if (canvas != null) { - super.onDraw(canvas); - } - mTotalWidth = 0; - if (mSuggestions == null) return; - - final int height = getHeight(); - if (mBgPadding == null) { - mBgPadding = new Rect(0, 0, 0, 0); - if (getBackground() != null) { - getBackground().getPadding(mBgPadding); - } - mDivider.setBounds(0, 0, mDivider.getIntrinsicWidth(), - mDivider.getIntrinsicHeight()); - } - int x = 0; - final int count = mSuggestions.size(); - final int width = getWidth(); - final Rect bgPadding = mBgPadding; - final Paint paint = mPaint; - final int touchX = mTouchX; - final int scrollX = getScrollX(); - final boolean scrolled = mScrolled; - final boolean typedWordValid = mTypedWordValid; - final int y = (int) (height + mPaint.getTextSize() - mDescent) / 2; - - for (int i = 0; i < count; i++) { - CharSequence suggestion = mSuggestions.get(i); - if (suggestion == null) continue; - paint.setColor(mColorNormal); - if (mHaveMinimalSuggestion - && ((i == 1 && !typedWordValid) || (i == 0 && typedWordValid))) { - paint.setTypeface(Typeface.DEFAULT_BOLD); - paint.setColor(mColorRecommended); - } else if (i != 0) { - paint.setColor(mColorOther); - } - final int wordWidth; - if (mWordWidth[i] != 0) { - wordWidth = mWordWidth[i]; - } else { - float textWidth = paint.measureText(suggestion, 0, suggestion.length()); - wordWidth = Math.max(mMinTouchableWidth, (int) textWidth + X_GAP * 2); - mWordWidth[i] = wordWidth; - } - - mWordX[i] = x; - - if (touchX + scrollX >= x && touchX + scrollX < x + wordWidth && !scrolled && - touchX != OUT_OF_BOUNDS) { - if (canvas != null && !mShowingAddToDictionary) { - canvas.translate(x, 0); - mSelectionHighlight.setBounds(0, bgPadding.top, wordWidth, height); - mSelectionHighlight.draw(canvas); - canvas.translate(-x, 0); - showPreview(i, null); - } - mSelectedString = suggestion; - mSelectedIndex = i; - } - - if (canvas != null) { - canvas.drawText(suggestion, 0, suggestion.length(), x + wordWidth / 2, y, paint); - paint.setColor(mColorOther); - canvas.translate(x + wordWidth, 0); - // Draw a divider unless it's after the hint - if (!(mShowingAddToDictionary && i == 1)) { - mDivider.draw(canvas); - } - canvas.translate(-x - wordWidth, 0); - } - paint.setTypeface(Typeface.DEFAULT); - x += wordWidth; - } - mTotalWidth = x; - if (mTargetScrollX != scrollX) { - scrollToTarget(); - } - } - - private void scrollToTarget() { - int scrollX = getScrollX(); - if (mTargetScrollX > scrollX) { - scrollX += SCROLL_PIXELS; - if (scrollX >= mTargetScrollX) { - scrollX = mTargetScrollX; - scrollTo(scrollX, getScrollY()); - requestLayout(); - } else { - scrollTo(scrollX, getScrollY()); - } - } else { - scrollX -= SCROLL_PIXELS; - if (scrollX <= mTargetScrollX) { - scrollX = mTargetScrollX; - scrollTo(scrollX, getScrollY()); - requestLayout(); - } else { - scrollTo(scrollX, getScrollY()); - } - } - invalidate(); - } - - public void setSuggestions(List<CharSequence> suggestions, boolean completions, - boolean typedWordValid, boolean haveMinimalSuggestion) { - clear(); - if (suggestions != null) { - mSuggestions = new ArrayList<CharSequence>(suggestions); - } - mShowingCompletions = completions; - mTypedWordValid = typedWordValid; - scrollTo(0, getScrollY()); - mTargetScrollX = 0; - mHaveMinimalSuggestion = haveMinimalSuggestion; - // Compute the total width - onDraw(null); - invalidate(); - requestLayout(); - } - - public void showAddToDictionaryHint(CharSequence word) { - mWordToAddToDictionary = word; - ArrayList<CharSequence> suggestions = new ArrayList<CharSequence>(); - suggestions.add(word); - suggestions.add(mAddToDictionaryHint); - setSuggestions(suggestions, false, false, false); - mShowingAddToDictionary = true; - } - - public void scrollPrev() { - int i = 0; - final int count = mSuggestions.size(); - int firstItem = 0; // Actually just before the first item, if at the boundary - while (i < count) { - if (mWordX[i] < getScrollX() - && mWordX[i] + mWordWidth[i] >= getScrollX() - 1) { - firstItem = i; - break; - } - i++; - } - int leftEdge = mWordX[firstItem] + mWordWidth[firstItem] - getWidth(); - if (leftEdge < 0) leftEdge = 0; - updateScrollPosition(leftEdge); - } - - public void scrollNext() { - int i = 0; - int scrollX = getScrollX(); - int targetX = scrollX; - final int count = mSuggestions.size(); - int rightEdge = scrollX + getWidth(); - while (i < count) { - if (mWordX[i] <= rightEdge && - mWordX[i] + mWordWidth[i] >= rightEdge) { - targetX = Math.min(mWordX[i], mTotalWidth - getWidth()); - break; - } - i++; - } - updateScrollPosition(targetX); - } - - private void updateScrollPosition(int targetX) { - if (targetX != getScrollX()) { - // TODO: Animate - mTargetScrollX = targetX; - requestLayout(); - invalidate(); - mScrolled = true; - } - } - - public void clear() { - mSuggestions = EMPTY_LIST; - mTouchX = OUT_OF_BOUNDS; - mSelectedString = null; - mSelectedIndex = -1; - mShowingAddToDictionary = false; - invalidate(); - Arrays.fill(mWordWidth, 0); - Arrays.fill(mWordX, 0); - if (mPreviewPopup.isShowing()) { - mPreviewPopup.dismiss(); - } - } - - @Override - public boolean onTouchEvent(MotionEvent me) { - - if (mGestureDetector.onTouchEvent(me)) { - return true; - } - - int action = me.getAction(); - int x = (int) me.getX(); - int y = (int) me.getY(); - mTouchX = x; - - switch (action) { - case MotionEvent.ACTION_DOWN: - mScrolled = false; - invalidate(); - break; - case MotionEvent.ACTION_MOVE: - if (y <= 0) { - // Fling up!? - if (mSelectedString != null) { - if (!mShowingCompletions) { - TextEntryState.acceptedSuggestion(mSuggestions.get(0), - mSelectedString); - } - mService.pickSuggestionManually(mSelectedIndex, mSelectedString); - mSelectedString = null; - mSelectedIndex = -1; - } - } - invalidate(); - break; - case MotionEvent.ACTION_UP: - if (!mScrolled) { - if (mSelectedString != null) { - if (mShowingAddToDictionary) { - longPressFirstWord(); - clear(); - } else { - if (!mShowingCompletions) { - TextEntryState.acceptedSuggestion(mSuggestions.get(0), - mSelectedString); - } - mService.pickSuggestionManually(mSelectedIndex, mSelectedString); - } - } - } - mSelectedString = null; - mSelectedIndex = -1; - removeHighlight(); - hidePreview(); - requestLayout(); - break; - } - return true; - } - - /** - * For flick through from keyboard, call this method with the x coordinate of the flick - * gesture. - * @param x - */ - public void takeSuggestionAt(float x) { - mTouchX = (int) x; - // To detect candidate - onDraw(null); - if (mSelectedString != null) { - if (!mShowingCompletions) { - TextEntryState.acceptedSuggestion(mSuggestions.get(0), mSelectedString); - } - mService.pickSuggestionManually(mSelectedIndex, mSelectedString); - } - invalidate(); - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_REMOVE_THROUGH_PREVIEW), 200); - } - - private void hidePreview() { - mCurrentWordIndex = OUT_OF_BOUNDS; - if (mPreviewPopup.isShowing()) { - mHandler.sendMessageDelayed(mHandler - .obtainMessage(MSG_REMOVE_PREVIEW), 60); - } - } - - private void showPreview(int wordIndex, String altText) { - int oldWordIndex = mCurrentWordIndex; - mCurrentWordIndex = wordIndex; - // If index changed or changing text - if (oldWordIndex != mCurrentWordIndex || altText != null) { - if (wordIndex == OUT_OF_BOUNDS) { - hidePreview(); - } else { - CharSequence word = altText != null? altText : mSuggestions.get(wordIndex); - mPreviewText.setText(word); - mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); - int wordWidth = (int) (mPaint.measureText(word, 0, word.length()) + X_GAP * 2); - final int popupWidth = wordWidth - + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight(); - final int popupHeight = mPreviewText.getMeasuredHeight(); - //mPreviewText.setVisibility(INVISIBLE); - mPopupPreviewX = mWordX[wordIndex] - mPreviewText.getPaddingLeft() - getScrollX() - + (mWordWidth[wordIndex] - wordWidth) / 2; - mPopupPreviewY = - popupHeight; - mHandler.removeMessages(MSG_REMOVE_PREVIEW); - int [] offsetInWindow = new int[2]; - getLocationInWindow(offsetInWindow); - if (mPreviewPopup.isShowing()) { - mPreviewPopup.update(mPopupPreviewX, mPopupPreviewY + offsetInWindow[1], - popupWidth, popupHeight); - } else { - mPreviewPopup.setWidth(popupWidth); - mPreviewPopup.setHeight(popupHeight); - mPreviewPopup.showAtLocation(this, Gravity.NO_GRAVITY, mPopupPreviewX, - mPopupPreviewY + offsetInWindow[1]); - } - mPreviewText.setVisibility(VISIBLE); - } - } - } - - private void removeHighlight() { - mTouchX = OUT_OF_BOUNDS; - invalidate(); - } - - private void longPressFirstWord() { - CharSequence word = mSuggestions.get(0); - if (word.length() < 2) return; - if (mService.addWordToDictionary(word.toString())) { - showPreview(0, getContext().getResources().getString(R.string.added_word, word)); - } - } - - @Override - public void onDetachedFromWindow() { - super.onDetachedFromWindow(); - hidePreview(); - } -} diff --git a/src/com/android/inputmethod/latin/CandidateViewContainer.java b/src/com/android/inputmethod/latin/CandidateViewContainer.java deleted file mode 100644 index e13f2738c..000000000 --- a/src/com/android/inputmethod/latin/CandidateViewContainer.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; -import android.widget.LinearLayout; - -public class CandidateViewContainer extends LinearLayout implements OnTouchListener { - - private View mButtonLeft; - private View mButtonRight; - private View mButtonLeftLayout; - private View mButtonRightLayout; - private CandidateView mCandidates; - - public CandidateViewContainer(Context screen, AttributeSet attrs) { - super(screen, attrs); - } - - public void initViews() { - if (mCandidates == null) { - mButtonLeftLayout = findViewById(R.id.candidate_left_parent); - mButtonLeft = findViewById(R.id.candidate_left); - if (mButtonLeft != null) { - mButtonLeft.setOnTouchListener(this); - } - mButtonRightLayout = findViewById(R.id.candidate_right_parent); - mButtonRight = findViewById(R.id.candidate_right); - if (mButtonRight != null) { - mButtonRight.setOnTouchListener(this); - } - mCandidates = (CandidateView) findViewById(R.id.candidates); - } - } - - @Override - public void requestLayout() { - if (mCandidates != null) { - int availableWidth = mCandidates.getWidth(); - int neededWidth = mCandidates.computeHorizontalScrollRange(); - int x = mCandidates.getScrollX(); - boolean leftVisible = x > 0; - boolean rightVisible = x + availableWidth < neededWidth; - if (mButtonLeftLayout != null) { - mButtonLeftLayout.setVisibility(leftVisible ? VISIBLE : GONE); - } - if (mButtonRightLayout != null) { - mButtonRightLayout.setVisibility(rightVisible ? VISIBLE : GONE); - } - } - super.requestLayout(); - } - - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - if (v == mButtonRight) { - mCandidates.scrollNext(); - } else if (v == mButtonLeft) { - mCandidates.scrollPrev(); - } - } - return false; - } - -} diff --git a/src/com/android/inputmethod/latin/ContactsDictionary.java b/src/com/android/inputmethod/latin/ContactsDictionary.java deleted file mode 100644 index f53ebf3f5..000000000 --- a/src/com/android/inputmethod/latin/ContactsDictionary.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin; - -import android.content.ContentResolver; -import android.content.Context; -import android.database.ContentObserver; -import android.database.Cursor; -import android.os.AsyncTask; -import android.os.SystemClock; -import android.provider.ContactsContract.Contacts; - -public class ContactsDictionary extends ExpandableDictionary { - - private static final String[] PROJECTION = { - Contacts._ID, - Contacts.DISPLAY_NAME, - }; - - private static final int INDEX_NAME = 1; - - private ContentObserver mObserver; - - private boolean mRequiresReload; - - private long mLastLoadedContacts; - - private boolean mUpdatingContacts; - - // Use this lock before touching mUpdatingContacts & mRequiresDownload - private Object mUpdatingLock = new Object(); - - public ContactsDictionary(Context context) { - super(context); - // Perform a managed query. The Activity will handle closing and requerying the cursor - // when needed. - ContentResolver cres = context.getContentResolver(); - - cres.registerContentObserver(Contacts.CONTENT_URI, true, mObserver = new ContentObserver(null) { - @Override - public void onChange(boolean self) { - synchronized (mUpdatingLock) { - mRequiresReload = true; - } - } - }); - - synchronized (mUpdatingLock) { - loadDictionaryAsyncLocked(); - } - } - - public synchronized void close() { - if (mObserver != null) { - getContext().getContentResolver().unregisterContentObserver(mObserver); - mObserver = null; - } - } - - private synchronized void loadDictionaryAsyncLocked() { - long now = SystemClock.uptimeMillis(); - if (mLastLoadedContacts == 0 - || now - mLastLoadedContacts > 30 * 60 * 1000 /* 30 minutes */) { - if (!mUpdatingContacts) { - mUpdatingContacts = true; - mRequiresReload = false; - new LoadContactsTask().execute(); - } - } - } - - @Override - public synchronized void getWords(final WordComposer codes, final WordCallback callback, - int[] nextLettersFrequencies) { - synchronized (mUpdatingLock) { - // If we need to update, start off a background task - if (mRequiresReload) loadDictionaryAsyncLocked(); - // Currently updating contacts, don't return any results. - if (mUpdatingContacts) return; - } - super.getWords(codes, callback, nextLettersFrequencies); - } - - @Override - public synchronized boolean isValidWord(CharSequence word) { - synchronized (mUpdatingLock) { - // If we need to update, start off a background task - if (mRequiresReload) loadDictionaryAsyncLocked(); - if (mUpdatingContacts) return false; - } - - return super.isValidWord(word); - } - - private void addWords(Cursor cursor) { - clearDictionary(); - - final int maxWordLength = getMaxWordLength(); - if (cursor.moveToFirst()) { - while (!cursor.isAfterLast()) { - String name = cursor.getString(INDEX_NAME); - - if (name != null) { - int len = name.length(); - - // TODO: Better tokenization for non-Latin writing systems - for (int i = 0; i < len; i++) { - if (Character.isLetter(name.charAt(i))) { - int j; - for (j = i + 1; j < len; j++) { - char c = name.charAt(j); - - if (!(c == '-' || c == '\'' || - Character.isLetter(c))) { - break; - } - } - - String word = name.substring(i, j); - i = j - 1; - - // Safeguard against adding really long words. Stack - // may overflow due to recursion - // Also don't add single letter words, possibly confuses - // capitalization of i. - final int wordLen = word.length(); - if (wordLen < maxWordLength && wordLen > 1) { - super.addWord(word, 128); - } - } - } - } - - cursor.moveToNext(); - } - } - cursor.close(); - } - - private class LoadContactsTask extends AsyncTask<Void, Void, Void> { - @Override - protected Void doInBackground(Void... v) { - Cursor cursor = getContext().getContentResolver() - .query(Contacts.CONTENT_URI, PROJECTION, null, null, null); - if (cursor != null) { - addWords(cursor); - } - mLastLoadedContacts = SystemClock.uptimeMillis(); - return null; - } - - @Override - protected void onPostExecute(Void result) { - // TODO Auto-generated method stub - synchronized (mUpdatingLock) { - mUpdatingContacts = false; - } - super.onPostExecute(result); - } - - } -} diff --git a/src/com/android/inputmethod/latin/Dictionary.java b/src/com/android/inputmethod/latin/Dictionary.java deleted file mode 100644 index b656d04dc..000000000 --- a/src/com/android/inputmethod/latin/Dictionary.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * 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; - -/** - * Abstract base class for a dictionary that can do a fuzzy search for words based on a set of key - * strokes. - */ -abstract public class Dictionary { - - /** - * Whether or not to replicate the typed word in the suggested list, even if it's valid. - */ - protected static final boolean INCLUDE_TYPED_WORD_IF_VALID = false; - - /** - * The weight to give to a word if it's length is the same as the number of typed characters. - */ - protected static final int FULL_WORD_FREQ_MULTIPLIER = 2; - - /** - * Interface to be implemented by classes requesting words to be fetched from the dictionary. - * @see #getWords(WordComposer, WordCallback) - */ - public interface WordCallback { - /** - * Adds a word to a list of suggestions. The word is expected to be ordered based on - * the provided frequency. - * @param word the character array containing the word - * @param wordOffset starting offset of the word in the character array - * @param wordLength length of valid characters in the character array - * @param frequency the frequency of occurence. This is normalized between 1 and 255, but - * can exceed those limits - * @return true if the word was added, false if no more words are required - */ - boolean addWord(char[] word, int wordOffset, int wordLength, int frequency); - } - - /** - * Searches for words in the dictionary that match the characters in the composer. Matched - * words are added through the callback object. - * @param composer the key sequence to match - * @param callback the callback object to send matched words to as possible candidates - * @param nextLettersFrequencies array of frequencies of next letters that could follow the - * word so far. For instance, "bracke" can be followed by "t", so array['t'] will have - * a non-zero value on returning from this method. - * Pass in null if you don't want the dictionary to look up next letters. - * @see WordCallback#addWord(char[], int, int) - */ - abstract public void getWords(final WordComposer composer, final WordCallback callback, - int[] nextLettersFrequencies); - - /** - * Checks if the given word occurs in the dictionary - * @param word the word to search for. The search should be case-insensitive. - * @return true if the word exists, false otherwise - */ - abstract public boolean isValidWord(CharSequence word); - - /** - * Compares the contents of the character array with the typed word and returns true if they - * are the same. - * @param word the array of characters that make up the word - * @param length the number of valid characters in the character array - * @param typedWord the word to compare with - * @return true if they are the same, false otherwise. - */ - protected boolean same(final char[] word, final int length, final CharSequence typedWord) { - if (typedWord.length() != length) { - return false; - } - for (int i = 0; i < length; i++) { - if (word[i] != typedWord.charAt(i)) { - return false; - } - } - return true; - } - - /** - * Override to clean up any resources. - */ - public void close() { - } -} diff --git a/src/com/android/inputmethod/latin/ExpandableDictionary.java b/src/com/android/inputmethod/latin/ExpandableDictionary.java deleted file mode 100644 index 006593700..000000000 --- a/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ /dev/null @@ -1,465 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin; - -import android.content.Context; - -/** - * Base class for an in-memory dictionary that can grow dynamically and can - * be searched for suggestions and valid words. - */ -public class ExpandableDictionary extends Dictionary { - private Context mContext; - private char[] mWordBuilder = new char[MAX_WORD_LENGTH]; - private int mMaxDepth; - private int mInputLength; - private int[] mNextLettersFrequencies; - - public static final int MAX_WORD_LENGTH = 32; - private static final char QUOTE = '\''; - - static class Node { - char code; - int frequency; - boolean terminal; - NodeArray children; - } - - static class NodeArray { - Node[] data; - int length = 0; - private static final int INCREMENT = 2; - - NodeArray() { - data = new Node[INCREMENT]; - } - - void add(Node n) { - if (length + 1 > data.length) { - Node[] tempData = new Node[length + INCREMENT]; - if (length > 0) { - System.arraycopy(data, 0, tempData, 0, length); - } - data = tempData; - } - data[length++] = n; - } - } - - private NodeArray mRoots; - - private int[][] mCodes; - - ExpandableDictionary(Context context) { - mContext = context; - clearDictionary(); - mCodes = new int[MAX_WORD_LENGTH][]; - } - - Context getContext() { - return mContext; - } - - int getMaxWordLength() { - return MAX_WORD_LENGTH; - } - - public void addWord(String word, int frequency) { - addWordRec(mRoots, word, 0, frequency); - } - - private void addWordRec(NodeArray children, final String word, - final int depth, final int frequency) { - - final int wordLength = word.length(); - final char c = word.charAt(depth); - // Does children have the current character? - final int childrenLength = children.length; - Node childNode = null; - boolean found = false; - for (int i = 0; i < childrenLength; i++) { - childNode = children.data[i]; - if (childNode.code == c) { - found = true; - break; - } - } - if (!found) { - childNode = new Node(); - childNode.code = c; - children.add(childNode); - } - if (wordLength == depth + 1) { - // Terminate this word - childNode.terminal = true; - childNode.frequency = Math.max(frequency, childNode.frequency); - if (childNode.frequency > 255) childNode.frequency = 255; - return; - } - if (childNode.children == null) { - childNode.children = new NodeArray(); - } - addWordRec(childNode.children, word, depth + 1, frequency); - } - - @Override - public void getWords(final WordComposer codes, final WordCallback callback, - int[] nextLettersFrequencies) { - mInputLength = codes.size(); - mNextLettersFrequencies = nextLettersFrequencies; - if (mCodes.length < mInputLength) mCodes = new int[mInputLength][]; - // Cache the codes so that we don't have to lookup an array list - for (int i = 0; i < mInputLength; i++) { - mCodes[i] = codes.getCodesAt(i); - } - mMaxDepth = mInputLength * 3; - getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, -1, callback); - for (int i = 0; i < mInputLength; i++) { - getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, i, callback); - } - } - - @Override - public synchronized boolean isValidWord(CharSequence word) { - final int freq = getWordFrequencyRec(mRoots, word, 0, word.length()); - return freq > -1; - } - - /** - * Returns the word's frequency or -1 if not found - */ - public int getWordFrequency(CharSequence word) { - return getWordFrequencyRec(mRoots, word, 0, word.length()); - } - - /** - * Returns the word's frequency or -1 if not found - */ - private int getWordFrequencyRec(final NodeArray children, final CharSequence word, - final int offset, final int length) { - final int count = children.length; - char currentChar = word.charAt(offset); - for (int j = 0; j < count; j++) { - final Node node = children.data[j]; - if (node.code == currentChar) { - if (offset == length - 1) { - if (node.terminal) { - return node.frequency; - } - } else { - if (node.children != null) { - int freq = getWordFrequencyRec(node.children, word, offset + 1, length); - if (freq > -1) return freq; - } - } - } - } - return -1; - } - - /** - * Recursively traverse the tree for words that match the input. Input consists of - * a list of arrays. Each item in the list is one input character position. An input - * character is actually an array of multiple possible candidates. This function is not - * optimized for speed, assuming that the user dictionary will only be a few hundred words in - * size. - * @param roots node whose children have to be search for matches - * @param codes the input character codes - * @param word the word being composed as a possible match - * @param depth the depth of traversal - the length of the word being composed thus far - * @param completion whether the traversal is now in completion mode - meaning that we've - * exhausted the input and we're looking for all possible suffixes. - * @param snr current weight of the word being formed - * @param inputIndex position in the input characters. This can be off from the depth in - * case we skip over some punctuations such as apostrophe in the traversal. That is, if you type - * "wouldve", it could be matching "would've", so the depth will be one more than the - * inputIndex - * @param callback the callback class for adding a word - */ - protected void getWordsRec(NodeArray roots, final WordComposer codes, final char[] word, - final int depth, boolean completion, int snr, int inputIndex, int skipPos, - WordCallback callback) { - final int count = roots.length; - final int codeSize = mInputLength; - // Optimization: Prune out words that are too long compared to how much was typed. - if (depth > mMaxDepth) { - return; - } - int[] currentChars = null; - if (codeSize <= inputIndex) { - completion = true; - } else { - currentChars = mCodes[inputIndex]; - } - - for (int i = 0; i < count; i++) { - final Node node = roots.data[i]; - final char c = node.code; - final char lowerC = toLowerCase(c); - final boolean terminal = node.terminal; - final NodeArray children = node.children; - final int freq = node.frequency; - if (completion) { - word[depth] = c; - if (terminal) { - if (!callback.addWord(word, 0, depth + 1, freq * snr)) { - return; - } - // Add to frequency of next letters for predictive correction - if (mNextLettersFrequencies != null && depth >= inputIndex && skipPos < 0 - && mNextLettersFrequencies.length > word[inputIndex]) { - mNextLettersFrequencies[word[inputIndex]]++; - } - } - if (children != null) { - getWordsRec(children, codes, word, depth + 1, completion, snr, inputIndex, - skipPos, callback); - } - } else if ((c == QUOTE && currentChars[0] != QUOTE) || depth == skipPos) { - // Skip the ' and continue deeper - word[depth] = c; - if (children != null) { - getWordsRec(children, codes, word, depth + 1, completion, snr, inputIndex, - skipPos, callback); - } - } else { - // Don't use alternatives if we're looking for missing characters - final int alternativesSize = skipPos >= 0? 1 : currentChars.length; - for (int j = 0; j < alternativesSize; j++) { - final int addedAttenuation = (j > 0 ? 1 : 2); - final int currentChar = currentChars[j]; - if (currentChar == -1) { - break; - } - if (currentChar == lowerC || currentChar == c) { - word[depth] = c; - - if (codeSize == inputIndex + 1) { - if (terminal) { - if (INCLUDE_TYPED_WORD_IF_VALID - || !same(word, depth + 1, codes.getTypedWord())) { - int finalFreq = freq * snr * addedAttenuation; - if (skipPos < 0) finalFreq *= FULL_WORD_FREQ_MULTIPLIER; - callback.addWord(word, 0, depth + 1, finalFreq); - } - } - if (children != null) { - getWordsRec(children, codes, word, depth + 1, - true, snr * addedAttenuation, inputIndex + 1, - skipPos, callback); - } - } else if (children != null) { - getWordsRec(children, codes, word, depth + 1, - false, snr * addedAttenuation, inputIndex + 1, - skipPos, callback); - } - } - } - } - } - } - - protected void clearDictionary() { - mRoots = new NodeArray(); - } - - static char toLowerCase(char c) { - if (c < BASE_CHARS.length) { - c = BASE_CHARS[c]; - } - if (c >= 'A' && c <= 'Z') { - c = (char) (c | 32); - } else if (c > 127) { - c = Character.toLowerCase(c); - } - return c; - } - - /** - * Table mapping most combined Latin, Greek, and Cyrillic characters - * to their base characters. If c is in range, BASE_CHARS[c] == c - * if c is not a combined character, or the base character if it - * is combined. - */ - static final char BASE_CHARS[] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, - 0x0020, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, - 0x0020, 0x00a9, 0x0061, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0020, - 0x00b0, 0x00b1, 0x0032, 0x0033, 0x0020, 0x03bc, 0x00b6, 0x00b7, - 0x0020, 0x0031, 0x006f, 0x00bb, 0x0031, 0x0031, 0x0033, 0x00bf, - 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x00c6, 0x0043, - 0x0045, 0x0045, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049, - 0x00d0, 0x004e, 0x004f, 0x004f, 0x004f, 0x004f, 0x004f, 0x00d7, - 0x004f, 0x0055, 0x0055, 0x0055, 0x0055, 0x0059, 0x00de, 0x0073, // Manually changed d8 to 4f - // Manually changed df to 73 - 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x00e6, 0x0063, - 0x0065, 0x0065, 0x0065, 0x0065, 0x0069, 0x0069, 0x0069, 0x0069, - 0x00f0, 0x006e, 0x006f, 0x006f, 0x006f, 0x006f, 0x006f, 0x00f7, - 0x006f, 0x0075, 0x0075, 0x0075, 0x0075, 0x0079, 0x00fe, 0x0079, // Manually changed f8 to 6f - 0x0041, 0x0061, 0x0041, 0x0061, 0x0041, 0x0061, 0x0043, 0x0063, - 0x0043, 0x0063, 0x0043, 0x0063, 0x0043, 0x0063, 0x0044, 0x0064, - 0x0110, 0x0111, 0x0045, 0x0065, 0x0045, 0x0065, 0x0045, 0x0065, - 0x0045, 0x0065, 0x0045, 0x0065, 0x0047, 0x0067, 0x0047, 0x0067, - 0x0047, 0x0067, 0x0047, 0x0067, 0x0048, 0x0068, 0x0126, 0x0127, - 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, - 0x0049, 0x0131, 0x0049, 0x0069, 0x004a, 0x006a, 0x004b, 0x006b, - 0x0138, 0x004c, 0x006c, 0x004c, 0x006c, 0x004c, 0x006c, 0x004c, - 0x006c, 0x0141, 0x0142, 0x004e, 0x006e, 0x004e, 0x006e, 0x004e, - 0x006e, 0x02bc, 0x014a, 0x014b, 0x004f, 0x006f, 0x004f, 0x006f, - 0x004f, 0x006f, 0x0152, 0x0153, 0x0052, 0x0072, 0x0052, 0x0072, - 0x0052, 0x0072, 0x0053, 0x0073, 0x0053, 0x0073, 0x0053, 0x0073, - 0x0053, 0x0073, 0x0054, 0x0074, 0x0054, 0x0074, 0x0166, 0x0167, - 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, - 0x0055, 0x0075, 0x0055, 0x0075, 0x0057, 0x0077, 0x0059, 0x0079, - 0x0059, 0x005a, 0x007a, 0x005a, 0x007a, 0x005a, 0x007a, 0x0073, - 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185, 0x0186, 0x0187, - 0x0188, 0x0189, 0x018a, 0x018b, 0x018c, 0x018d, 0x018e, 0x018f, - 0x0190, 0x0191, 0x0192, 0x0193, 0x0194, 0x0195, 0x0196, 0x0197, - 0x0198, 0x0199, 0x019a, 0x019b, 0x019c, 0x019d, 0x019e, 0x019f, - 0x004f, 0x006f, 0x01a2, 0x01a3, 0x01a4, 0x01a5, 0x01a6, 0x01a7, - 0x01a8, 0x01a9, 0x01aa, 0x01ab, 0x01ac, 0x01ad, 0x01ae, 0x0055, - 0x0075, 0x01b1, 0x01b2, 0x01b3, 0x01b4, 0x01b5, 0x01b6, 0x01b7, - 0x01b8, 0x01b9, 0x01ba, 0x01bb, 0x01bc, 0x01bd, 0x01be, 0x01bf, - 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x0044, 0x0044, 0x0064, 0x004c, - 0x004c, 0x006c, 0x004e, 0x004e, 0x006e, 0x0041, 0x0061, 0x0049, - 0x0069, 0x004f, 0x006f, 0x0055, 0x0075, 0x00dc, 0x00fc, 0x00dc, - 0x00fc, 0x00dc, 0x00fc, 0x00dc, 0x00fc, 0x01dd, 0x00c4, 0x00e4, - 0x0226, 0x0227, 0x00c6, 0x00e6, 0x01e4, 0x01e5, 0x0047, 0x0067, - 0x004b, 0x006b, 0x004f, 0x006f, 0x01ea, 0x01eb, 0x01b7, 0x0292, - 0x006a, 0x0044, 0x0044, 0x0064, 0x0047, 0x0067, 0x01f6, 0x01f7, - 0x004e, 0x006e, 0x00c5, 0x00e5, 0x00c6, 0x00e6, 0x00d8, 0x00f8, - 0x0041, 0x0061, 0x0041, 0x0061, 0x0045, 0x0065, 0x0045, 0x0065, - 0x0049, 0x0069, 0x0049, 0x0069, 0x004f, 0x006f, 0x004f, 0x006f, - 0x0052, 0x0072, 0x0052, 0x0072, 0x0055, 0x0075, 0x0055, 0x0075, - 0x0053, 0x0073, 0x0054, 0x0074, 0x021c, 0x021d, 0x0048, 0x0068, - 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0041, 0x0061, - 0x0045, 0x0065, 0x00d6, 0x00f6, 0x00d5, 0x00f5, 0x004f, 0x006f, - 0x022e, 0x022f, 0x0059, 0x0079, 0x0234, 0x0235, 0x0236, 0x0237, - 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f, - 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, - 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f, - 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257, - 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f, - 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267, - 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f, - 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, - 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, - 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, - 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f, - 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, - 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, - 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, - 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, - 0x0068, 0x0266, 0x006a, 0x0072, 0x0279, 0x027b, 0x0281, 0x0077, - 0x0079, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, - 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, - 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, - 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, - 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x02de, 0x02df, - 0x0263, 0x006c, 0x0073, 0x0078, 0x0295, 0x02e5, 0x02e6, 0x02e7, - 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, - 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, - 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff, - 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, - 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, - 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, - 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, - 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, - 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, - 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, - 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, - 0x0300, 0x0301, 0x0342, 0x0313, 0x0308, 0x0345, 0x0346, 0x0347, - 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f, - 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, - 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f, - 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, - 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, - 0x0370, 0x0371, 0x0372, 0x0373, 0x02b9, 0x0375, 0x0376, 0x0377, - 0x0378, 0x0379, 0x0020, 0x037b, 0x037c, 0x037d, 0x003b, 0x037f, - 0x0380, 0x0381, 0x0382, 0x0383, 0x0020, 0x00a8, 0x0391, 0x00b7, - 0x0395, 0x0397, 0x0399, 0x038b, 0x039f, 0x038d, 0x03a5, 0x03a9, - 0x03ca, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, - 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, - 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, - 0x03a8, 0x03a9, 0x0399, 0x03a5, 0x03b1, 0x03b5, 0x03b7, 0x03b9, - 0x03cb, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, - 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, - 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, - 0x03c8, 0x03c9, 0x03b9, 0x03c5, 0x03bf, 0x03c5, 0x03c9, 0x03cf, - 0x03b2, 0x03b8, 0x03a5, 0x03d2, 0x03d2, 0x03c6, 0x03c0, 0x03d7, - 0x03d8, 0x03d9, 0x03da, 0x03db, 0x03dc, 0x03dd, 0x03de, 0x03df, - 0x03e0, 0x03e1, 0x03e2, 0x03e3, 0x03e4, 0x03e5, 0x03e6, 0x03e7, - 0x03e8, 0x03e9, 0x03ea, 0x03eb, 0x03ec, 0x03ed, 0x03ee, 0x03ef, - 0x03ba, 0x03c1, 0x03c2, 0x03f3, 0x0398, 0x03b5, 0x03f6, 0x03f7, - 0x03f8, 0x03a3, 0x03fa, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff, - 0x0415, 0x0415, 0x0402, 0x0413, 0x0404, 0x0405, 0x0406, 0x0406, - 0x0408, 0x0409, 0x040a, 0x040b, 0x041a, 0x0418, 0x0423, 0x040f, - 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, - 0x0418, 0x0418, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, - 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, - 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, - 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0438, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, - 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, - 0x0435, 0x0435, 0x0452, 0x0433, 0x0454, 0x0455, 0x0456, 0x0456, - 0x0458, 0x0459, 0x045a, 0x045b, 0x043a, 0x0438, 0x0443, 0x045f, - 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, - 0x0468, 0x0469, 0x046a, 0x046b, 0x046c, 0x046d, 0x046e, 0x046f, - 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0474, 0x0475, - 0x0478, 0x0479, 0x047a, 0x047b, 0x047c, 0x047d, 0x047e, 0x047f, - 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, - 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f, - 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, - 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x049f, - 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, - 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af, - 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, - 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x04be, 0x04bf, - 0x04c0, 0x0416, 0x0436, 0x04c3, 0x04c4, 0x04c5, 0x04c6, 0x04c7, - 0x04c8, 0x04c9, 0x04ca, 0x04cb, 0x04cc, 0x04cd, 0x04ce, 0x04cf, - 0x0410, 0x0430, 0x0410, 0x0430, 0x04d4, 0x04d5, 0x0415, 0x0435, - 0x04d8, 0x04d9, 0x04d8, 0x04d9, 0x0416, 0x0436, 0x0417, 0x0437, - 0x04e0, 0x04e1, 0x0418, 0x0438, 0x0418, 0x0438, 0x041e, 0x043e, - 0x04e8, 0x04e9, 0x04e8, 0x04e9, 0x042d, 0x044d, 0x0423, 0x0443, - 0x0423, 0x0443, 0x0423, 0x0443, 0x0427, 0x0447, 0x04f6, 0x04f7, - 0x042b, 0x044b, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff, - }; - - // generated with: - // cat UnicodeData.txt | perl -e 'while (<>) { @foo = split(/;/); $foo[5] =~ s/<.*> //; $base[hex($foo[0])] = hex($foo[5]);} for ($i = 0; $i < 0x500; $i += 8) { for ($j = $i; $j < $i + 8; $j++) { printf("0x%04x, ", $base[$j] ? $base[$j] : $j)}; print "\n"; }' - -} diff --git a/src/com/android/inputmethod/latin/Hints.java b/src/com/android/inputmethod/latin/Hints.java deleted file mode 100644 index 689c8d852..000000000 --- a/src/com/android/inputmethod/latin/Hints.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import com.android.inputmethod.voice.SettingsUtil; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.view.inputmethod.InputConnection; - -import java.util.Calendar; -import java.util.HashMap; -import java.util.Map; - -/** - * Logic to determine when to display hints on usage to the user. - */ -public class Hints { - public interface Display { - public void showHint(int viewResource); - } - - private static final String TAG = "Hints"; - private static final String PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN = - "voice_hint_num_unique_days_shown"; - private static final String PREF_VOICE_HINT_LAST_TIME_SHOWN = - "voice_hint_last_time_shown"; - private static final String PREF_VOICE_INPUT_LAST_TIME_USED = - "voice_input_last_time_used"; - private static final String PREF_VOICE_PUNCTUATION_HINT_VIEW_COUNT = - "voice_punctuation_hint_view_count"; - private static final int DEFAULT_SWIPE_HINT_MAX_DAYS_TO_SHOW = 7; - private static final int DEFAULT_PUNCTUATION_HINT_MAX_DISPLAYS = 7; - - private Context mContext; - private Display mDisplay; - private boolean mVoiceResultContainedPunctuation; - private int mSwipeHintMaxDaysToShow; - private int mPunctuationHintMaxDisplays; - - // Only show punctuation hint if voice result did not contain punctuation. - static final Map<CharSequence, String> SPEAKABLE_PUNCTUATION - = new HashMap<CharSequence, String>(); - static { - SPEAKABLE_PUNCTUATION.put(",", "comma"); - SPEAKABLE_PUNCTUATION.put(".", "period"); - SPEAKABLE_PUNCTUATION.put("?", "question mark"); - } - - public Hints(Context context, Display display) { - mContext = context; - mDisplay = display; - - ContentResolver cr = mContext.getContentResolver(); - mSwipeHintMaxDaysToShow = SettingsUtil.getSettingsInt( - cr, - SettingsUtil.LATIN_IME_VOICE_INPUT_SWIPE_HINT_MAX_DAYS, - DEFAULT_SWIPE_HINT_MAX_DAYS_TO_SHOW); - mPunctuationHintMaxDisplays = SettingsUtil.getSettingsInt( - cr, - SettingsUtil.LATIN_IME_VOICE_INPUT_PUNCTUATION_HINT_MAX_DISPLAYS, - DEFAULT_PUNCTUATION_HINT_MAX_DISPLAYS); - } - - public boolean showSwipeHintIfNecessary(boolean fieldRecommended) { - if (fieldRecommended && shouldShowSwipeHint()) { - showHint(R.layout.voice_swipe_hint); - return true; - } - - return false; - } - - public boolean showPunctuationHintIfNecessary(InputConnection ic) { - if (!mVoiceResultContainedPunctuation - && ic != null - && getAndIncrementPref(PREF_VOICE_PUNCTUATION_HINT_VIEW_COUNT) - < mPunctuationHintMaxDisplays) { - CharSequence charBeforeCursor = ic.getTextBeforeCursor(1, 0); - if (SPEAKABLE_PUNCTUATION.containsKey(charBeforeCursor)) { - showHint(R.layout.voice_punctuation_hint); - return true; - } - } - - return false; - } - - public void registerVoiceResult(String text) { - // Update the current time as the last time voice input was used. - SharedPreferences.Editor editor = - PreferenceManager.getDefaultSharedPreferences(mContext).edit(); - editor.putLong(PREF_VOICE_INPUT_LAST_TIME_USED, System.currentTimeMillis()); - editor.commit(); - - mVoiceResultContainedPunctuation = false; - for (CharSequence s : SPEAKABLE_PUNCTUATION.keySet()) { - if (text.indexOf(s.toString()) >= 0) { - mVoiceResultContainedPunctuation = true; - break; - } - } - } - - private boolean shouldShowSwipeHint() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); - - int numUniqueDaysShown = sp.getInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, 0); - - // If we've already shown the hint for enough days, we'll return false. - if (numUniqueDaysShown < mSwipeHintMaxDaysToShow) { - - long lastTimeVoiceWasUsed = sp.getLong(PREF_VOICE_INPUT_LAST_TIME_USED, 0); - - // If the user has used voice today, we'll return false. (We don't show the hint on - // any day that the user has already used voice.) - if (!isFromToday(lastTimeVoiceWasUsed)) { - return true; - } - } - - return false; - } - - /** - * Determines whether the provided time is from some time today (i.e., this day, month, - * and year). - */ - private boolean isFromToday(long timeInMillis) { - if (timeInMillis == 0) return false; - - Calendar today = Calendar.getInstance(); - today.setTimeInMillis(System.currentTimeMillis()); - - Calendar timestamp = Calendar.getInstance(); - timestamp.setTimeInMillis(timeInMillis); - - return (today.get(Calendar.YEAR) == timestamp.get(Calendar.YEAR) && - today.get(Calendar.DAY_OF_MONTH) == timestamp.get(Calendar.DAY_OF_MONTH) && - today.get(Calendar.MONTH) == timestamp.get(Calendar.MONTH)); - } - - private void showHint(int hintViewResource) { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); - - int numUniqueDaysShown = sp.getInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, 0); - long lastTimeHintWasShown = sp.getLong(PREF_VOICE_HINT_LAST_TIME_SHOWN, 0); - - // If this is the first time the hint is being shown today, increase the saved values - // to represent that. We don't need to increase the last time the hint was shown unless - // it is a different day from the current value. - if (!isFromToday(lastTimeHintWasShown)) { - SharedPreferences.Editor editor = sp.edit(); - editor.putInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, numUniqueDaysShown + 1); - editor.putLong(PREF_VOICE_HINT_LAST_TIME_SHOWN, System.currentTimeMillis()); - editor.commit(); - } - - if (mDisplay != null) { - mDisplay.showHint(hintViewResource); - } - } - - private int getAndIncrementPref(String pref) { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); - int value = sp.getInt(pref, 0); - SharedPreferences.Editor editor = sp.edit(); - editor.putInt(pref, value + 1); - editor.commit(); - return value; - } -} diff --git a/src/com/android/inputmethod/latin/InputLanguageSelection.java b/src/com/android/inputmethod/latin/InputLanguageSelection.java deleted file mode 100644 index b1ddb2175..000000000 --- a/src/com/android/inputmethod/latin/InputLanguageSelection.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import java.text.Collator; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Locale; - -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.PreferenceActivity; -import android.preference.PreferenceGroup; -import android.preference.PreferenceManager; -import android.text.TextUtils; - -public class InputLanguageSelection extends PreferenceActivity { - - private String mSelectedLanguages; - private ArrayList<Loc> mAvailableLanguages = new ArrayList<Loc>(); - private static final String[] BLACKLIST_LANGUAGES = { - "ko", "ja", "zh" - }; - - private static class Loc implements Comparable { - static Collator sCollator = Collator.getInstance(); - - String label; - Locale locale; - - public Loc(String label, Locale locale) { - this.label = label; - this.locale = locale; - } - - @Override - public String toString() { - return this.label; - } - - public int compareTo(Object o) { - return sCollator.compare(this.label, ((Loc) o).label); - } - } - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - addPreferencesFromResource(R.xml.language_prefs); - // Get the settings preferences - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - mSelectedLanguages = sp.getString(LatinIME.PREF_SELECTED_LANGUAGES, ""); - String[] languageList = mSelectedLanguages.split(","); - mAvailableLanguages = getUniqueLocales(); - PreferenceGroup parent = getPreferenceScreen(); - for (int i = 0; i < mAvailableLanguages.size(); i++) { - CheckBoxPreference pref = new CheckBoxPreference(this); - Locale locale = mAvailableLanguages.get(i).locale; - pref.setTitle(LanguageSwitcher.toTitleCase(locale.getDisplayName(locale))); - boolean checked = isLocaleIn(locale, languageList); - pref.setChecked(checked); - parent.addPreference(pref); - } - } - - private boolean isLocaleIn(Locale locale, String[] list) { - String lang = get5Code(locale); - for (int i = 0; i < list.length; i++) { - if (lang.equalsIgnoreCase(list[i])) return true; - } - // If it matches the current locale - Locale displayLocale = getResources().getConfiguration().locale; - if (lang.equalsIgnoreCase(get5Code(displayLocale))) { - return true; - } - return false; - } - - private String get5Code(Locale locale) { - String country = locale.getCountry(); - return locale.getLanguage() - + (TextUtils.isEmpty(country) ? "" : "_" + country); - } - - @Override - protected void onResume() { - super.onResume(); - } - - @Override - protected void onPause() { - super.onPause(); - // Save the selected languages - String checkedLanguages = ""; - PreferenceGroup parent = getPreferenceScreen(); - int count = parent.getPreferenceCount(); - for (int i = 0; i < count; i++) { - CheckBoxPreference pref = (CheckBoxPreference) parent.getPreference(i); - if (pref.isChecked()) { - Locale locale = mAvailableLanguages.get(i).locale; - checkedLanguages += get5Code(locale) + ","; - } - } - if (checkedLanguages.length() < 1) checkedLanguages = null; // Save null - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - Editor editor = sp.edit(); - editor.putString(LatinIME.PREF_SELECTED_LANGUAGES, checkedLanguages); - editor.commit(); - } - - ArrayList<Loc> getUniqueLocales() { - String[] locales = getAssets().getLocales(); - Arrays.sort(locales); - ArrayList<Loc> uniqueLocales = new ArrayList<Loc>(); - - final int origSize = locales.length; - Loc[] preprocess = new Loc[origSize]; - int finalSize = 0; - for (int i = 0 ; i < origSize; i++ ) { - String s = locales[i]; - int len = s.length(); - if (len == 5) { - String language = s.substring(0, 2); - String country = s.substring(3, 5); - Locale l = new Locale(language, country); - - // Exclude languages that are not relevant to LatinIME - if (arrayContains(BLACKLIST_LANGUAGES, language)) continue; - - if (finalSize == 0) { - preprocess[finalSize++] = - new Loc(LanguageSwitcher.toTitleCase(l.getDisplayName(l)), 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].locale.getLanguage().equals( - language)) { - preprocess[finalSize-1].label = LanguageSwitcher.toTitleCase( - preprocess[finalSize-1].locale.getDisplayName()); - preprocess[finalSize++] = - new Loc(LanguageSwitcher.toTitleCase(l.getDisplayName()), l); - } else { - String displayName; - if (s.equals("zz_ZZ")) { - } else { - displayName = LanguageSwitcher.toTitleCase(l.getDisplayName(l)); - preprocess[finalSize++] = new Loc(displayName, l); - } - } - } - } - } - for (int i = 0; i < finalSize ; i++) { - uniqueLocales.add(preprocess[i]); - } - return uniqueLocales; - } - - private boolean arrayContains(String[] array, String value) { - for (int i = 0; i < array.length; i++) { - if (array[i].equalsIgnoreCase(value)) return true; - } - return false; - } -} diff --git a/src/com/android/inputmethod/latin/KeyboardSwitcher.java b/src/com/android/inputmethod/latin/KeyboardSwitcher.java deleted file mode 100644 index 438680cf8..000000000 --- a/src/com/android/inputmethod/latin/KeyboardSwitcher.java +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (C) 2008 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.inputmethodservice.InputMethodService; - -public class KeyboardSwitcher { - - public static final int MODE_TEXT = 1; - public static final int MODE_SYMBOLS = 2; - public static final int MODE_PHONE = 3; - public static final int MODE_URL = 4; - public static final int MODE_EMAIL = 5; - public static final int MODE_IM = 6; - public static final int MODE_WEB = 7; - - public static final int MODE_TEXT_QWERTY = 0; - public static final int MODE_TEXT_ALPHA = 1; - public static final int MODE_TEXT_COUNT = 2; - - public static final int KEYBOARDMODE_NORMAL = R.id.mode_normal; - public static final int KEYBOARDMODE_URL = R.id.mode_url; - public static final int KEYBOARDMODE_EMAIL = R.id.mode_email; - public static final int KEYBOARDMODE_IM = R.id.mode_im; - public static final int KEYBOARDMODE_WEB = R.id.mode_webentry; - - private static final int SYMBOLS_MODE_STATE_NONE = 0; - private static final int SYMBOLS_MODE_STATE_BEGIN = 1; - private static final int SYMBOLS_MODE_STATE_SYMBOL = 2; - - LatinKeyboardView mInputView; - private static final int[] ALPHABET_MODES = { - KEYBOARDMODE_NORMAL, - KEYBOARDMODE_URL, - KEYBOARDMODE_EMAIL, - KEYBOARDMODE_IM, - KEYBOARDMODE_WEB}; - - //LatinIME mContext; - Context mContext; - InputMethodService mInputMethodService; - - private KeyboardId mSymbolsId; - private KeyboardId mSymbolsShiftedId; - - private KeyboardId mCurrentId; - private Map<KeyboardId, LatinKeyboard> mKeyboards; - - private int mMode; /** One of the MODE_XXX values */ - private int mImeOptions; - private int mTextMode = MODE_TEXT_QWERTY; - private boolean mIsSymbols; - private boolean mHasVoice; - private boolean mVoiceOnPrimary; - private boolean mPreferSymbols; - private int mSymbolsModeState = SYMBOLS_MODE_STATE_NONE; - - private int mLastDisplayWidth; - private LanguageSwitcher mLanguageSwitcher; - private Locale mInputLocale; - private boolean mEnableMultipleLanguages; - - KeyboardSwitcher(Context context, InputMethodService ims) { - mContext = context; - mKeyboards = new HashMap<KeyboardId, LatinKeyboard>(); - mSymbolsId = new KeyboardId(R.xml.kbd_symbols, false); - mSymbolsShiftedId = new KeyboardId(R.xml.kbd_symbols_shift, false); - mInputMethodService = ims; - } - - /** - * Sets the input locale, when there are multiple locales for input. - * If no locale switching is required, then the locale should be set to null. - * @param locale the current input locale, or null for default locale with no locale - * button. - */ - void setLanguageSwitcher(LanguageSwitcher languageSwitcher) { - mLanguageSwitcher = languageSwitcher; - mInputLocale = mLanguageSwitcher.getInputLocale(); - mEnableMultipleLanguages = mLanguageSwitcher.getLocaleCount() > 1; - } - - void setInputView(LatinKeyboardView inputView) { - mInputView = inputView; - } - - void makeKeyboards(boolean forceCreate) { - if (forceCreate) mKeyboards.clear(); - // Configuration change is coming after the keyboard gets recreated. So don't rely on that. - // If keyboards have already been made, check if we have a screen width change and - // create the keyboard layouts again at the correct orientation - int displayWidth = mInputMethodService.getMaxWidth(); - if (displayWidth == mLastDisplayWidth) return; - mLastDisplayWidth = displayWidth; - if (!forceCreate) mKeyboards.clear(); - mSymbolsId = new KeyboardId(R.xml.kbd_symbols, mHasVoice && !mVoiceOnPrimary); - mSymbolsShiftedId = new KeyboardId(R.xml.kbd_symbols_shift, - mHasVoice && !mVoiceOnPrimary); - } - - /** - * Represents the parameters necessary to construct a new LatinKeyboard, - * which also serve as a unique identifier for each keyboard type. - */ - private static class KeyboardId { - public int mXml; - public int mKeyboardMode; /** A KEYBOARDMODE_XXX value */ - public boolean mEnableShiftLock; - public boolean mHasVoice; - - public KeyboardId(int xml, int mode, boolean enableShiftLock, boolean hasVoice) { - this.mXml = xml; - this.mKeyboardMode = mode; - this.mEnableShiftLock = enableShiftLock; - this.mHasVoice = hasVoice; - } - - public KeyboardId(int xml, boolean hasVoice) { - this(xml, 0, false, hasVoice); - } - - public boolean equals(Object other) { - return other instanceof KeyboardId && equals((KeyboardId) other); - } - - public boolean equals(KeyboardId other) { - return other.mXml == this.mXml - && other.mKeyboardMode == this.mKeyboardMode - && other.mEnableShiftLock == this.mEnableShiftLock; - } - - public int hashCode() { - return (mXml + 1) * (mKeyboardMode + 1) * (mEnableShiftLock ? 2 : 1) - * (mHasVoice ? 4 : 8); - } - } - - void setVoiceMode(boolean enableVoice, boolean voiceOnPrimary) { - if (enableVoice != mHasVoice || voiceOnPrimary != mVoiceOnPrimary) { - mKeyboards.clear(); - } - mHasVoice = enableVoice; - mVoiceOnPrimary = voiceOnPrimary; - setKeyboardMode(mMode, mImeOptions, mHasVoice, - mIsSymbols); - } - - boolean hasVoiceButton(boolean isSymbols) { - return mHasVoice && (isSymbols != mVoiceOnPrimary); - } - - void setKeyboardMode(int mode, int imeOptions, boolean enableVoice) { - mSymbolsModeState = SYMBOLS_MODE_STATE_NONE; - mPreferSymbols = mode == MODE_SYMBOLS; - setKeyboardMode(mode == MODE_SYMBOLS ? MODE_TEXT : mode, imeOptions, enableVoice, - mPreferSymbols); - } - - void setKeyboardMode(int mode, int imeOptions, boolean enableVoice, boolean isSymbols) { - if (mInputView == null) return; - mMode = mode; - mImeOptions = imeOptions; - if (enableVoice != mHasVoice) { - setVoiceMode(mHasVoice, mVoiceOnPrimary); - } - mIsSymbols = isSymbols; - - mInputView.setPreviewEnabled(true); - KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols); - - LatinKeyboard keyboard = getKeyboard(id); - - if (mode == MODE_PHONE) { - mInputView.setPhoneKeyboard(keyboard); - mInputView.setPreviewEnabled(false); - } - - mCurrentId = id; - mInputView.setKeyboard(keyboard); - keyboard.setShifted(false); - keyboard.setShiftLocked(keyboard.isShiftLocked()); - keyboard.setImeOptions(mContext.getResources(), mMode, imeOptions); - } - - private LatinKeyboard getKeyboard(KeyboardId id) { - if (!mKeyboards.containsKey(id)) { - Resources orig = mContext.getResources(); - Configuration conf = orig.getConfiguration(); - Locale saveLocale = conf.locale; - conf.locale = mInputLocale; - orig.updateConfiguration(conf, null); - LatinKeyboard keyboard = new LatinKeyboard( - mContext, id.mXml, id.mKeyboardMode); - keyboard.setVoiceMode(hasVoiceButton(id.mXml == R.xml.kbd_symbols), mHasVoice); - keyboard.setLanguageSwitcher(mLanguageSwitcher); - if (id.mKeyboardMode == KEYBOARDMODE_NORMAL - || id.mKeyboardMode == KEYBOARDMODE_URL - || id.mKeyboardMode == KEYBOARDMODE_IM - || id.mKeyboardMode == KEYBOARDMODE_EMAIL - || id.mKeyboardMode == KEYBOARDMODE_WEB - ) { - keyboard.setExtension(R.xml.kbd_extension); - } - - if (id.mEnableShiftLock) { - keyboard.enableShiftLock(); - } - mKeyboards.put(id, keyboard); - - conf.locale = saveLocale; - orig.updateConfiguration(conf, null); - } - return mKeyboards.get(id); - } - - private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) { - boolean hasVoice = hasVoiceButton(isSymbols); - if (isSymbols) { - return (mode == MODE_PHONE) - ? new KeyboardId(R.xml.kbd_phone_symbols, hasVoice) - : new KeyboardId(R.xml.kbd_symbols, hasVoice); - } - switch (mode) { - case MODE_TEXT: - if (mTextMode == MODE_TEXT_QWERTY) { - return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_NORMAL, true, hasVoice); - } else if (mTextMode == MODE_TEXT_ALPHA) { - return new KeyboardId(R.xml.kbd_alpha, KEYBOARDMODE_NORMAL, true, hasVoice); - } - break; - case MODE_SYMBOLS: - return new KeyboardId(R.xml.kbd_symbols, hasVoice); - case MODE_PHONE: - return new KeyboardId(R.xml.kbd_phone, hasVoice); - case MODE_URL: - return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_URL, true, hasVoice); - case MODE_EMAIL: - return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_EMAIL, true, hasVoice); - case MODE_IM: - return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_IM, true, hasVoice); - case MODE_WEB: - return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_WEB, true, hasVoice); - } - return null; - } - - int getKeyboardMode() { - return mMode; - } - - boolean isTextMode() { - return mMode == MODE_TEXT; - } - - int getTextMode() { - return mTextMode; - } - - void setTextMode(int position) { - if (position < MODE_TEXT_COUNT && position >= 0) { - mTextMode = position; - } - if (isTextMode()) { - setKeyboardMode(MODE_TEXT, mImeOptions, mHasVoice); - } - } - - int getTextModeCount() { - return MODE_TEXT_COUNT; - } - - boolean isAlphabetMode() { - int currentMode = mCurrentId.mKeyboardMode; - for (Integer mode : ALPHABET_MODES) { - if (currentMode == mode) { - return true; - } - } - return false; - } - - void toggleShift() { - if (mCurrentId.equals(mSymbolsId)) { - LatinKeyboard symbolsKeyboard = getKeyboard(mSymbolsId); - LatinKeyboard symbolsShiftedKeyboard = getKeyboard(mSymbolsShiftedId); - symbolsKeyboard.setShifted(true); - mCurrentId = mSymbolsShiftedId; - mInputView.setKeyboard(symbolsShiftedKeyboard); - symbolsShiftedKeyboard.setShifted(true); - symbolsShiftedKeyboard.setImeOptions(mContext.getResources(), mMode, mImeOptions); - } else if (mCurrentId.equals(mSymbolsShiftedId)) { - LatinKeyboard symbolsKeyboard = getKeyboard(mSymbolsId); - LatinKeyboard symbolsShiftedKeyboard = getKeyboard(mSymbolsShiftedId); - symbolsShiftedKeyboard.setShifted(false); - mCurrentId = mSymbolsId; - mInputView.setKeyboard(getKeyboard(mSymbolsId)); - symbolsKeyboard.setShifted(false); - symbolsKeyboard.setImeOptions(mContext.getResources(), mMode, mImeOptions); - } - } - - void toggleSymbols() { - setKeyboardMode(mMode, mImeOptions, mHasVoice, !mIsSymbols); - if (mIsSymbols && !mPreferSymbols) { - mSymbolsModeState = SYMBOLS_MODE_STATE_BEGIN; - } else { - mSymbolsModeState = SYMBOLS_MODE_STATE_NONE; - } - } - - /** - * Updates state machine to figure out when to automatically switch back to alpha mode. - * Returns true if the keyboard needs to switch back - */ - boolean onKey(int key) { - // Switch back to alpha mode if user types one or more non-space/enter characters - // followed by a space/enter - switch (mSymbolsModeState) { - case SYMBOLS_MODE_STATE_BEGIN: - if (key != LatinIME.KEYCODE_SPACE && key != LatinIME.KEYCODE_ENTER && key > 0) { - mSymbolsModeState = SYMBOLS_MODE_STATE_SYMBOL; - } - break; - case SYMBOLS_MODE_STATE_SYMBOL: - if (key == LatinIME.KEYCODE_ENTER || key == LatinIME.KEYCODE_SPACE) return true; - break; - } - return false; - } -} diff --git a/src/com/android/inputmethod/latin/LanguageSwitcher.java b/src/com/android/inputmethod/latin/LanguageSwitcher.java deleted file mode 100644 index 12045125f..000000000 --- a/src/com/android/inputmethod/latin/LanguageSwitcher.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import java.util.Locale; - -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.preference.PreferenceManager; -import android.text.TextUtils; - -/** - * Keeps track of list of selected input languages and the current - * input language that the user has selected. - */ -public class LanguageSwitcher { - - private Locale[] mLocales; - private LatinIME mIme; - private String[] mSelectedLanguageArray; - private String mSelectedLanguages; - private int mCurrentIndex = 0; - private String mDefaultInputLanguage; - private Locale mDefaultInputLocale; - - public LanguageSwitcher(LatinIME ime) { - mIme = ime; - mLocales = new Locale[0]; - } - - public Locale[] getLocales() { - return mLocales; - } - - public int getLocaleCount() { - return mLocales.length; - } - - /** - * Loads the currently selected input languages from shared preferences. - * @param sp - * @return whether there was any change - */ - public boolean loadLocales(SharedPreferences sp) { - String selectedLanguages = sp.getString(LatinIME.PREF_SELECTED_LANGUAGES, null); - String currentLanguage = sp.getString(LatinIME.PREF_INPUT_LANGUAGE, null); - if (selectedLanguages == null || selectedLanguages.length() < 1) { - loadDefaults(); - if (mLocales.length == 0) { - return false; - } - mLocales = new Locale[0]; - return true; - } - if (selectedLanguages.equals(mSelectedLanguages)) { - return false; - } - mSelectedLanguageArray = selectedLanguages.split(","); - mSelectedLanguages = selectedLanguages; // Cache it for comparison later - constructLocales(); - mCurrentIndex = 0; - if (currentLanguage != null) { - // Find the index - mCurrentIndex = 0; - for (int i = 0; i < mLocales.length; i++) { - if (mSelectedLanguageArray[i].equals(currentLanguage)) { - mCurrentIndex = i; - break; - } - } - // If we didn't find the index, use the first one - } - return true; - } - - private void loadDefaults() { - mDefaultInputLocale = mIme.getResources().getConfiguration().locale; - String country = mDefaultInputLocale.getCountry(); - mDefaultInputLanguage = mDefaultInputLocale.getLanguage() + - (TextUtils.isEmpty(country) ? "" : "_" + country); - } - - private void constructLocales() { - mLocales = new Locale[mSelectedLanguageArray.length]; - for (int i = 0; i < mLocales.length; i++) { - mLocales[i] = new Locale(mSelectedLanguageArray[i]); - } - } - - /** - * Returns the currently selected input language code, or the display language code if - * no specific locale was selected for input. - */ - public String getInputLanguage() { - if (getLocaleCount() == 0) return mDefaultInputLanguage; - - return mSelectedLanguageArray[mCurrentIndex]; - } - - /** - * Returns the list of enabled language codes. - */ - public String[] getEnabledLanguages() { - return mSelectedLanguageArray; - } - - /** - * Returns the currently selected input locale, or the display locale if no specific - * locale was selected for input. - * @return - */ - public Locale getInputLocale() { - if (getLocaleCount() == 0) return mDefaultInputLocale; - - return mLocales[mCurrentIndex]; - } - - /** - * Returns the next input locale in the list. Wraps around to the beginning of the - * list if we're at the end of the list. - * @return - */ - public Locale getNextInputLocale() { - if (getLocaleCount() == 0) return mDefaultInputLocale; - - return mLocales[(mCurrentIndex + 1) % mLocales.length]; - } - - /** - * Returns the previous input locale in the list. Wraps around to the end of the - * list if we're at the beginning of the list. - * @return - */ - public Locale getPrevInputLocale() { - if (getLocaleCount() == 0) return mDefaultInputLocale; - - return mLocales[(mCurrentIndex - 1 + mLocales.length) % mLocales.length]; - } - - public void reset() { - mCurrentIndex = 0; - } - - public void next() { - mCurrentIndex++; - if (mCurrentIndex >= mLocales.length) mCurrentIndex = 0; // Wrap around - } - - public void prev() { - mCurrentIndex--; - if (mCurrentIndex < 0) mCurrentIndex = mLocales.length - 1; // Wrap around - } - - public void persist() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mIme); - Editor editor = sp.edit(); - editor.putString(LatinIME.PREF_INPUT_LANGUAGE, getInputLanguage()); - editor.commit(); - } - - static String toTitleCase(String s) { - if (s.length() == 0) { - return s; - } - - return Character.toUpperCase(s.charAt(0)) + s.substring(1); - } -} diff --git a/src/com/android/inputmethod/latin/LatinIME.java b/src/com/android/inputmethod/latin/LatinIME.java deleted file mode 100644 index 43972d98b..000000000 --- a/src/com/android/inputmethod/latin/LatinIME.java +++ /dev/null @@ -1,1949 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import com.android.inputmethod.voice.EditingUtil; -import com.android.inputmethod.voice.FieldContext; -import com.android.inputmethod.voice.SettingsUtil; -import com.android.inputmethod.voice.VoiceInput; - -import android.app.AlertDialog; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.inputmethodservice.InputMethodService; -import android.inputmethodservice.Keyboard; -import android.inputmethodservice.KeyboardView; -import android.media.AudioManager; -import android.os.Debug; -import android.os.Handler; -import android.os.Message; -import android.os.SystemClock; -import android.preference.PreferenceManager; -import android.speech.RecognitionManager; -import android.text.AutoText; -import android.text.ClipboardManager; -import android.text.TextUtils; -import android.util.Log; -import android.util.PrintWriterPrinter; -import android.util.Printer; -import android.view.HapticFeedbackConstants; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewParent; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.view.inputmethod.CompletionInfo; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.ExtractedText; -import android.view.inputmethod.ExtractedTextRequest; -import android.view.inputmethod.InputConnection; -import android.view.inputmethod.InputMethodManager; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -/** - * Input method implementation for Qwerty'ish keyboard. - */ -public class LatinIME extends InputMethodService - implements KeyboardView.OnKeyboardActionListener, - VoiceInput.UiListener, - SharedPreferences.OnSharedPreferenceChangeListener { - private static final String TAG = "LatinIME"; - static final boolean DEBUG = false; - static final boolean TRACE = false; - static final boolean VOICE_INSTALLED = true; - static final boolean ENABLE_VOICE_BUTTON = true; - - private static final String PREF_VIBRATE_ON = "vibrate_on"; - private static final String PREF_SOUND_ON = "sound_on"; - private static final String PREF_AUTO_CAP = "auto_cap"; - private static final String PREF_QUICK_FIXES = "quick_fixes"; - private static final String PREF_SHOW_SUGGESTIONS = "show_suggestions"; - private static final String PREF_AUTO_COMPLETE = "auto_complete"; - private static final String PREF_VOICE_MODE = "voice_mode"; - - // Whether or not the user has used voice input before (and thus, whether to show the - // first-run warning dialog or not). - private static final String PREF_HAS_USED_VOICE_INPUT = "has_used_voice_input"; - - // Whether or not the user has used voice input from an unsupported locale UI before. - // For example, the user has a Chinese UI but activates voice input. - private static final String PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE = - "has_used_voice_input_unsupported_locale"; - - // A list of locales which are supported by default for voice input, unless we get a - // different list from Gservices. - public static final String DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES = - "en " + - "en_US " + - "en_GB " + - "en_AU " + - "en_CA " + - "en_IE " + - "en_IN " + - "en_NZ " + - "en_SG " + - "en_ZA "; - - // The private IME option used to indicate that no microphone should be shown for a - // given text field. For instance this is specified by the search dialog when the - // dialog is already showing a voice search button. - private static final String IME_OPTION_NO_MICROPHONE = "nm"; - - public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; - public static final String PREF_INPUT_LANGUAGE = "input_language"; - - private static final int MSG_UPDATE_SUGGESTIONS = 0; - private static final int MSG_START_TUTORIAL = 1; - private static final int MSG_UPDATE_SHIFT_STATE = 2; - private static final int MSG_VOICE_RESULTS = 3; - private static final int MSG_START_LISTENING_AFTER_SWIPE = 4; - - // If we detect a swipe gesture within N ms of typing, then swipe is - // ignored, since it may in fact be two key presses in quick succession. - private static final long MIN_MILLIS_AFTER_TYPING_BEFORE_SWIPE = 1000; - - // How many continuous deletes at which to start deleting at a higher speed. - private static final int DELETE_ACCELERATE_AT = 20; - // Key events coming any faster than this are long-presses. - private static final int QUICK_PRESS = 200; - - static final int KEYCODE_ENTER = '\n'; - static final int KEYCODE_SPACE = ' '; - static final int KEYCODE_PERIOD = '.'; - - // Contextual menu positions - private static final int POS_SETTINGS = 0; - private static final int POS_METHOD = 1; - - private LatinKeyboardView mInputView; - private CandidateViewContainer mCandidateViewContainer; - private CandidateView mCandidateView; - private Suggest mSuggest; - private CompletionInfo[] mCompletions; - - private AlertDialog mOptionsDialog; - private AlertDialog mVoiceWarningDialog; - - KeyboardSwitcher mKeyboardSwitcher; - - private UserDictionary mUserDictionary; - private ContactsDictionary mContactsDictionary; - private ExpandableDictionary mAutoDictionary; - - private Hints mHints; - - Resources mResources; - - private String mLocale; - private LanguageSwitcher mLanguageSwitcher; - - private StringBuilder mComposing = new StringBuilder(); - private WordComposer mWord = new WordComposer(); - private int mCommittedLength; - private boolean mPredicting; - private boolean mRecognizing; - private boolean mAfterVoiceInput; - private boolean mImmediatelyAfterVoiceInput; - private boolean mShowingVoiceSuggestions; - private boolean mImmediatelyAfterVoiceSuggestions; - private boolean mVoiceInputHighlighted; - private boolean mEnableVoiceButton; - private CharSequence mBestWord; - private boolean mPredictionOn; - private boolean mCompletionOn; - private boolean mHasDictionary; - private boolean mAutoSpace; - private boolean mJustAddedAutoSpace; - private boolean mAutoCorrectEnabled; - private boolean mAutoCorrectOn; - private boolean mCapsLock; - private boolean mPasswordText; - private boolean mEmailText; - private boolean mVibrateOn; - private boolean mSoundOn; - private boolean mAutoCap; - private boolean mQuickFixes; - private boolean mHasUsedVoiceInput; - private boolean mHasUsedVoiceInputUnsupportedLocale; - private boolean mLocaleSupportedForVoiceInput; - private boolean mShowSuggestions; - private boolean mSuggestionShouldReplaceCurrentWord; - private boolean mIsShowingHint; - private int mCorrectionMode; - private boolean mEnableVoice = true; - private boolean mVoiceOnPrimary; - private int mOrientation; - private List<CharSequence> mSuggestPuncList; - - // Indicates whether the suggestion strip is to be on in landscape - private boolean mJustAccepted; - private CharSequence mJustRevertedSeparator; - private int mDeleteCount; - private long mLastKeyTime; - - private Tutorial mTutorial; - - private AudioManager mAudioManager; - // Align sound effect volume on music volume - private final float FX_VOLUME = -1.0f; - private boolean mSilentMode; - - private String mWordSeparators; - private String mSentenceSeparators; - private VoiceInput mVoiceInput; - private VoiceResults mVoiceResults = new VoiceResults(); - private long mSwipeTriggerTimeMillis; - private boolean mConfigurationChanging; - - // For each word, a list of potential replacements, usually from voice. - private Map<String, List<CharSequence>> mWordToSuggestions = - new HashMap<String, List<CharSequence>>(); - - private class VoiceResults { - List<String> candidates; - Map<String, List<CharSequence>> alternatives; - } - private boolean mRefreshKeyboardRequired; - - Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_UPDATE_SUGGESTIONS: - updateSuggestions(); - break; - case MSG_START_TUTORIAL: - if (mTutorial == null) { - if (mInputView.isShown()) { - mTutorial = new Tutorial(LatinIME.this, mInputView); - mTutorial.start(); - } else { - // Try again soon if the view is not yet showing - sendMessageDelayed(obtainMessage(MSG_START_TUTORIAL), 100); - } - } - break; - case MSG_UPDATE_SHIFT_STATE: - updateShiftKeyState(getCurrentInputEditorInfo()); - break; - case MSG_VOICE_RESULTS: - handleVoiceResults(); - break; - case MSG_START_LISTENING_AFTER_SWIPE: - if (mLastKeyTime < mSwipeTriggerTimeMillis) { - startListening(true); - } - } - } - }; - - @Override public void onCreate() { - super.onCreate(); - //setStatusIcon(R.drawable.ime_qwerty); - mResources = getResources(); - final Configuration conf = mResources.getConfiguration(); - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - mLanguageSwitcher = new LanguageSwitcher(this); - mLanguageSwitcher.loadLocales(prefs); - mKeyboardSwitcher = new KeyboardSwitcher(this, this); - mKeyboardSwitcher.setLanguageSwitcher(mLanguageSwitcher); - boolean enableMultipleLanguages = mLanguageSwitcher.getLocaleCount() > 0; - String inputLanguage = mLanguageSwitcher.getInputLanguage(); - if (inputLanguage == null) { - inputLanguage = conf.locale.toString(); - } - initSuggest(inputLanguage); - mOrientation = conf.orientation; - initSuggestPuncList(); - - // register to receive ringer mode changes for silent mode - IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); - registerReceiver(mReceiver, filter); - if (VOICE_INSTALLED) { - mVoiceInput = new VoiceInput(this, this); - mHints = new Hints(this, new Hints.Display() { - public void showHint(int viewResource) { - LayoutInflater inflater = (LayoutInflater) getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - View view = inflater.inflate(viewResource, null); - setCandidatesView(view); - setCandidatesViewShown(true); - mIsShowingHint = true; - } - }); - } - prefs.registerOnSharedPreferenceChangeListener(this); - } - - private void initSuggest(String locale) { - mLocale = locale; - - Resources orig = getResources(); - Configuration conf = orig.getConfiguration(); - Locale saveLocale = conf.locale; - conf.locale = new Locale(locale); - orig.updateConfiguration(conf, orig.getDisplayMetrics()); - if (mSuggest != null) { - mSuggest.close(); - } - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - mQuickFixes = sp.getBoolean(PREF_QUICK_FIXES, true); - mSuggest = new Suggest(this, R.raw.main); - updateAutoTextEnabled(saveLocale); - if (mUserDictionary != null) mUserDictionary.close(); - mUserDictionary = new UserDictionary(this, mLocale); - if (mContactsDictionary == null) { - mContactsDictionary = new ContactsDictionary(this); - } - if (mAutoDictionary != null) { - mAutoDictionary.close(); - } - mAutoDictionary = new AutoDictionary(this, this, mLocale); - mSuggest.setUserDictionary(mUserDictionary); - mSuggest.setContactsDictionary(mContactsDictionary); - mSuggest.setAutoDictionary(mAutoDictionary); - updateCorrectionMode(); - mWordSeparators = mResources.getString(R.string.word_separators); - mSentenceSeparators = mResources.getString(R.string.sentence_separators); - - conf.locale = saveLocale; - orig.updateConfiguration(conf, orig.getDisplayMetrics()); - } - - @Override - public void onDestroy() { - mUserDictionary.close(); - mContactsDictionary.close(); - unregisterReceiver(mReceiver); - if (VOICE_INSTALLED) { - mVoiceInput.destroy(); - } - super.onDestroy(); - } - - @Override - public void onConfigurationChanged(Configuration conf) { - // If the system locale changes and is different from the saved - // locale (mLocale), then reload the input locale list from the - // latin ime settings (shared prefs) and reset the input locale - // to the first one. - if (!TextUtils.equals(conf.locale.toString(), mLocale)) { - if (mLanguageSwitcher != null) { - mLanguageSwitcher.loadLocales( - PreferenceManager.getDefaultSharedPreferences(this)); - toggleLanguage(true, true); - } else { - reloadKeyboards(); - } - } - // If orientation changed while predicting, commit the change - if (conf.orientation != mOrientation) { - InputConnection ic = getCurrentInputConnection(); - commitTyped(ic); - if (ic != null) ic.finishComposingText(); // For voice input - mOrientation = conf.orientation; - reloadKeyboards(); - } - mConfigurationChanging = true; - super.onConfigurationChanged(conf); - if (mRecognizing) { - switchToRecognitionStatusView(); - } - mConfigurationChanging = false; - } - - @Override - public View onCreateInputView() { - mInputView = (LatinKeyboardView) getLayoutInflater().inflate( - R.layout.input, null); - mKeyboardSwitcher.setInputView(mInputView); - mKeyboardSwitcher.makeKeyboards(true); - mInputView.setOnKeyboardActionListener(this); - mKeyboardSwitcher.setKeyboardMode( - KeyboardSwitcher.MODE_TEXT, 0, - shouldShowVoiceButton(makeFieldContext(), getCurrentInputEditorInfo())); - return mInputView; - } - - @Override - public View onCreateCandidatesView() { - mKeyboardSwitcher.makeKeyboards(true); - mCandidateViewContainer = (CandidateViewContainer) getLayoutInflater().inflate( - R.layout.candidates, null); - mCandidateViewContainer.initViews(); - mCandidateView = (CandidateView) mCandidateViewContainer.findViewById(R.id.candidates); - mCandidateView.setService(this); - setCandidatesViewShown(true); - return mCandidateViewContainer; - } - - @Override - public void onStartInputView(EditorInfo attribute, boolean restarting) { - // In landscape mode, this method gets called without the input view being created. - if (mInputView == null) { - return; - } - - if (mRefreshKeyboardRequired) { - mRefreshKeyboardRequired = false; - toggleLanguage(true, true); - } - - mKeyboardSwitcher.makeKeyboards(false); - - TextEntryState.newSession(this); - - // Most such things we decide below in the switch statement, but we need to know - // now whether this is a password text field, because we need to know now (before - // the switch statement) whether we want to enable the voice button. - mPasswordText = false; - int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION; - if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD || - variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) { - mPasswordText = true; - } - - mEnableVoiceButton = shouldShowVoiceButton(makeFieldContext(), attribute); - final boolean enableVoiceButton = mEnableVoiceButton && mEnableVoice; - - mAfterVoiceInput = false; - mImmediatelyAfterVoiceInput = false; - mShowingVoiceSuggestions = false; - mImmediatelyAfterVoiceSuggestions = false; - mVoiceInputHighlighted = false; - mWordToSuggestions.clear(); - mInputTypeNoAutoCorrect = false; - mPredictionOn = false; - mCompletionOn = false; - mCompletions = null; - mCapsLock = false; - mEmailText = false; - switch (attribute.inputType & EditorInfo.TYPE_MASK_CLASS) { - case EditorInfo.TYPE_CLASS_NUMBER: - case EditorInfo.TYPE_CLASS_DATETIME: - mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_SYMBOLS, - attribute.imeOptions, enableVoiceButton); - break; - case EditorInfo.TYPE_CLASS_PHONE: - mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_PHONE, - attribute.imeOptions, enableVoiceButton); - break; - case EditorInfo.TYPE_CLASS_TEXT: - mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT, - attribute.imeOptions, enableVoiceButton); - //startPrediction(); - mPredictionOn = true; - // Make sure that passwords are not displayed in candidate view - if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD || - variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD ) { - mPredictionOn = false; - } - if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) { - mEmailText = true; - } - if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS - || variation == EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME) { - mAutoSpace = false; - } else { - mAutoSpace = true; - } - if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) { - mPredictionOn = false; - mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_EMAIL, - attribute.imeOptions, enableVoiceButton); - } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_URI) { - mPredictionOn = false; - mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_URL, - attribute.imeOptions, enableVoiceButton); - } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE) { - mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_IM, - attribute.imeOptions, enableVoiceButton); - } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) { - mPredictionOn = false; - } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) { - mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_WEB, - attribute.imeOptions, enableVoiceButton); - // If it's a browser edit field and auto correct is not ON explicitly, then - // disable auto correction, but keep suggestions on. - if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) { - mInputTypeNoAutoCorrect = true; - } - } - - // If NO_SUGGESTIONS is set, don't do prediction. - if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) { - mPredictionOn = false; - mInputTypeNoAutoCorrect = true; - } - // If it's not multiline and the autoCorrect flag is not set, then don't correct - if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 && - (attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) == 0) { - mInputTypeNoAutoCorrect = true; - } - if ((attribute.inputType&EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) { - mPredictionOn = false; - mCompletionOn = true && isFullscreenMode(); - } - updateShiftKeyState(attribute); - break; - default: - mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT, - attribute.imeOptions, enableVoiceButton); - updateShiftKeyState(attribute); - } - mInputView.closing(); - mComposing.setLength(0); - mPredicting = false; - mDeleteCount = 0; - mJustAddedAutoSpace = false; - loadSettings(); - updateShiftKeyState(attribute); - - setCandidatesViewShown(false); - setSuggestions(null, false, false, false); - - // If the dictionary is not big enough, don't auto correct - mHasDictionary = mSuggest.hasMainDictionary(); - - updateCorrectionMode(); - - mInputView.setProximityCorrectionEnabled(true); - mPredictionOn = mPredictionOn && (mCorrectionMode > 0 || mShowSuggestions); - checkTutorial(attribute.privateImeOptions); - if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); - } - - @Override - public void onFinishInput() { - super.onFinishInput(); - - if (VOICE_INSTALLED && !mConfigurationChanging) { - if (mAfterVoiceInput) { - mVoiceInput.logInputEnded(); - } - mVoiceInput.flushLogs(); - mVoiceInput.cancel(); - } - if (mInputView != null) { - mInputView.closing(); - } - } - - @Override - public void onUpdateExtractedText(int token, ExtractedText text) { - super.onUpdateExtractedText(token, text); - InputConnection ic = getCurrentInputConnection(); - if (!mImmediatelyAfterVoiceInput && mAfterVoiceInput && ic != null) { - mVoiceInput.logTextModified(); - - if (mHints.showPunctuationHintIfNecessary(ic)) { - mVoiceInput.logPunctuationHintDisplayed(); - } - } - mImmediatelyAfterVoiceInput = false; - } - - @Override - public void onUpdateSelection(int oldSelStart, int oldSelEnd, - int newSelStart, int newSelEnd, - int candidatesStart, int candidatesEnd) { - super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, - candidatesStart, candidatesEnd); - - if (DEBUG) { - Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart - + ", ose=" + oldSelEnd - + ", nss=" + newSelStart - + ", nse=" + newSelEnd - + ", cs=" + candidatesStart - + ", ce=" + candidatesEnd); - } - - mSuggestionShouldReplaceCurrentWord = false; - // If the current selection in the text view changes, we should - // clear whatever candidate text we have. - if ((((mComposing.length() > 0 && mPredicting) || mVoiceInputHighlighted) - && (newSelStart != candidatesEnd - || newSelEnd != candidatesEnd))) { - mComposing.setLength(0); - mPredicting = false; - updateSuggestions(); - TextEntryState.reset(); - InputConnection ic = getCurrentInputConnection(); - if (ic != null) { - ic.finishComposingText(); - } - mVoiceInputHighlighted = false; - } else if (!mPredicting && !mJustAccepted) { - switch (TextEntryState.getState()) { - case TextEntryState.STATE_ACCEPTED_DEFAULT: - TextEntryState.reset(); - // fall through - case TextEntryState.STATE_SPACE_AFTER_PICKED: - mJustAddedAutoSpace = false; // The user moved the cursor. - break; - } - } - mJustAccepted = false; - postUpdateShiftKeyState(); - - if (VOICE_INSTALLED) { - if (mShowingVoiceSuggestions) { - if (mImmediatelyAfterVoiceSuggestions) { - mImmediatelyAfterVoiceSuggestions = false; - } else { - updateSuggestions(); - mShowingVoiceSuggestions = false; - } - } - if (VoiceInput.ENABLE_WORD_CORRECTIONS) { - // If we have alternatives for the current word, then show them. - String word = EditingUtil.getWordAtCursor( - getCurrentInputConnection(), getWordSeparators()); - if (word != null && mWordToSuggestions.containsKey(word.trim())) { - mSuggestionShouldReplaceCurrentWord = true; - final List<CharSequence> suggestions = mWordToSuggestions.get(word.trim()); - - setSuggestions(suggestions, false, true, true); - setCandidatesViewShown(true); - } - } - } - } - - @Override - public void hideWindow() { - if (TRACE) Debug.stopMethodTracing(); - if (mOptionsDialog != null && mOptionsDialog.isShowing()) { - mOptionsDialog.dismiss(); - mOptionsDialog = null; - } - if (!mConfigurationChanging) { - if (mAfterVoiceInput) mVoiceInput.logInputEnded(); - if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) { - mVoiceInput.logKeyboardWarningDialogDismissed(); - mVoiceWarningDialog.dismiss(); - mVoiceWarningDialog = null; - } - if (VOICE_INSTALLED & mRecognizing) { - mVoiceInput.cancel(); - } - } - super.hideWindow(); - TextEntryState.endSession(); - } - - @Override - public void onDisplayCompletions(CompletionInfo[] completions) { - if (false) { - Log.i("foo", "Received completions:"); - for (int i=0; i<(completions != null ? completions.length : 0); i++) { - Log.i("foo", " #" + i + ": " + completions[i]); - } - } - if (mCompletionOn) { - mCompletions = completions; - if (completions == null) { - setSuggestions(null, false, false, false); - return; - } - - List<CharSequence> stringList = new ArrayList<CharSequence>(); - for (int i=0; i<(completions != null ? completions.length : 0); i++) { - CompletionInfo ci = completions[i]; - if (ci != null) stringList.add(ci.getText()); - } - //CharSequence typedWord = mWord.getTypedWord(); - setSuggestions(stringList, true, true, true); - mBestWord = null; - setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn); - } - } - - @Override - public void setCandidatesViewShown(boolean shown) { - // TODO: Remove this if we support candidates with hard keyboard - if (onEvaluateInputViewShown()) { - super.setCandidatesViewShown(shown); - } - } - - @Override - public void onComputeInsets(InputMethodService.Insets outInsets) { - super.onComputeInsets(outInsets); - if (!isFullscreenMode()) { - outInsets.contentTopInsets = outInsets.visibleTopInsets; - } - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_BACK: - if (event.getRepeatCount() == 0 && mInputView != null) { - if (mInputView.handleBack()) { - return true; - } else if (mTutorial != null) { - mTutorial.close(); - mTutorial = null; - } - } - break; - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_LEFT: - case KeyEvent.KEYCODE_DPAD_RIGHT: - // If tutorial is visible, don't allow dpad to work - if (mTutorial != null) { - return true; - } - break; - } - return super.onKeyDown(keyCode, event); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_LEFT: - case KeyEvent.KEYCODE_DPAD_RIGHT: - // If tutorial is visible, don't allow dpad to work - if (mTutorial != null) { - return true; - } - // Enable shift key and DPAD to do selections - if (mInputView != null && mInputView.isShown() && mInputView.isShifted()) { - event = new KeyEvent(event.getDownTime(), event.getEventTime(), - event.getAction(), event.getKeyCode(), event.getRepeatCount(), - event.getDeviceId(), event.getScanCode(), - KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON); - InputConnection ic = getCurrentInputConnection(); - if (ic != null) ic.sendKeyEvent(event); - return true; - } - break; - } - return super.onKeyUp(keyCode, event); - } - - private void revertVoiceInput() { - InputConnection ic = getCurrentInputConnection(); - if (ic != null) ic.commitText("", 1); - updateSuggestions(); - mVoiceInputHighlighted = false; - } - - private void commitVoiceInput() { - InputConnection ic = getCurrentInputConnection(); - if (ic != null) ic.finishComposingText(); - updateSuggestions(); - mVoiceInputHighlighted = false; - } - - private void reloadKeyboards() { - if (mKeyboardSwitcher == null) { - mKeyboardSwitcher = new KeyboardSwitcher(this, this); - } - mKeyboardSwitcher.setLanguageSwitcher(mLanguageSwitcher); - if (mInputView != null) { - mKeyboardSwitcher.setVoiceMode(mEnableVoice && mEnableVoiceButton, mVoiceOnPrimary); - } - mKeyboardSwitcher.makeKeyboards(true); - } - - private void commitTyped(InputConnection inputConnection) { - if (mPredicting) { - mPredicting = false; - if (mComposing.length() > 0) { - if (inputConnection != null) { - inputConnection.commitText(mComposing, 1); - } - mCommittedLength = mComposing.length(); - TextEntryState.acceptedTyped(mComposing); - checkAddToDictionary(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED); - } - updateSuggestions(); - } - } - - private void postUpdateShiftKeyState() { - mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE); - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SHIFT_STATE), 300); - } - - public void updateShiftKeyState(EditorInfo attr) { - InputConnection ic = getCurrentInputConnection(); - if (attr != null && mInputView != null && mKeyboardSwitcher.isAlphabetMode() - && ic != null) { - mInputView.setShifted(mCapsLock || getCursorCapsMode(ic, attr) != 0); - } - } - - private int getCursorCapsMode(InputConnection ic, EditorInfo attr) { - int caps = 0; - EditorInfo ei = getCurrentInputEditorInfo(); - if (mAutoCap && ei != null && ei.inputType != EditorInfo.TYPE_NULL) { - caps = ic.getCursorCapsMode(attr.inputType); - } - return caps; - } - - private void swapPunctuationAndSpace() { - final InputConnection ic = getCurrentInputConnection(); - if (ic == null) return; - CharSequence lastTwo = ic.getTextBeforeCursor(2, 0); - if (lastTwo != null && lastTwo.length() == 2 - && lastTwo.charAt(0) == KEYCODE_SPACE && isSentenceSeparator(lastTwo.charAt(1))) { - ic.beginBatchEdit(); - ic.deleteSurroundingText(2, 0); - ic.commitText(lastTwo.charAt(1) + " ", 1); - ic.endBatchEdit(); - updateShiftKeyState(getCurrentInputEditorInfo()); - mJustAddedAutoSpace = true; - } - } - - private void reswapPeriodAndSpace() { - final InputConnection ic = getCurrentInputConnection(); - if (ic == null) return; - CharSequence lastThree = ic.getTextBeforeCursor(3, 0); - if (lastThree != null && lastThree.length() == 3 - && lastThree.charAt(0) == KEYCODE_PERIOD - && lastThree.charAt(1) == KEYCODE_SPACE - && lastThree.charAt(2) == KEYCODE_PERIOD) { - ic.beginBatchEdit(); - ic.deleteSurroundingText(3, 0); - ic.commitText(" ..", 1); - ic.endBatchEdit(); - updateShiftKeyState(getCurrentInputEditorInfo()); - } - } - - private void doubleSpace() { - //if (!mAutoPunctuate) return; - if (mCorrectionMode == Suggest.CORRECTION_NONE) return; - final InputConnection ic = getCurrentInputConnection(); - if (ic == null) return; - CharSequence lastThree = ic.getTextBeforeCursor(3, 0); - if (lastThree != null && lastThree.length() == 3 - && Character.isLetterOrDigit(lastThree.charAt(0)) - && lastThree.charAt(1) == KEYCODE_SPACE && lastThree.charAt(2) == KEYCODE_SPACE) { - ic.beginBatchEdit(); - ic.deleteSurroundingText(2, 0); - ic.commitText(". ", 1); - ic.endBatchEdit(); - updateShiftKeyState(getCurrentInputEditorInfo()); - mJustAddedAutoSpace = true; - } - } - - private void maybeRemovePreviousPeriod(CharSequence text) { - final InputConnection ic = getCurrentInputConnection(); - if (ic == null) return; - - // When the text's first character is '.', remove the previous period - // if there is one. - CharSequence lastOne = ic.getTextBeforeCursor(1, 0); - if (lastOne != null && lastOne.length() == 1 - && lastOne.charAt(0) == KEYCODE_PERIOD - && text.charAt(0) == KEYCODE_PERIOD) { - ic.deleteSurroundingText(1, 0); - } - } - - private void removeTrailingSpace() { - final InputConnection ic = getCurrentInputConnection(); - if (ic == null) return; - - CharSequence lastOne = ic.getTextBeforeCursor(1, 0); - if (lastOne != null && lastOne.length() == 1 - && lastOne.charAt(0) == KEYCODE_SPACE) { - ic.deleteSurroundingText(1, 0); - } - } - - public boolean addWordToDictionary(String word) { - mUserDictionary.addWord(word, 128); - return true; - } - - private boolean isAlphabet(int code) { - if (Character.isLetter(code)) { - return true; - } else { - return false; - } - } - - // Implementation of KeyboardViewListener - - public void onKey(int primaryCode, int[] keyCodes) { - long when = SystemClock.uptimeMillis(); - if (primaryCode != Keyboard.KEYCODE_DELETE || - when > mLastKeyTime + QUICK_PRESS) { - mDeleteCount = 0; - } - mLastKeyTime = when; - switch (primaryCode) { - case Keyboard.KEYCODE_DELETE: - handleBackspace(); - mDeleteCount++; - break; - case Keyboard.KEYCODE_SHIFT: - handleShift(); - break; - case Keyboard.KEYCODE_CANCEL: - if (mOptionsDialog == null || !mOptionsDialog.isShowing()) { - handleClose(); - } - break; - case LatinKeyboardView.KEYCODE_OPTIONS: - showOptionsMenu(); - break; - case LatinKeyboardView.KEYCODE_NEXT_LANGUAGE: - toggleLanguage(false, true); - break; - case LatinKeyboardView.KEYCODE_PREV_LANGUAGE: - toggleLanguage(false, false); - break; - case LatinKeyboardView.KEYCODE_SHIFT_LONGPRESS: - if (mCapsLock) { - handleShift(); - } else { - toggleCapsLock(); - } - break; - case Keyboard.KEYCODE_MODE_CHANGE: - changeKeyboardMode(); - break; - case LatinKeyboardView.KEYCODE_VOICE: - if (VOICE_INSTALLED) { - startListening(false /* was a button press, was not a swipe */); - } - break; - case 9 /*Tab*/: - sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB); - break; - default: - if (primaryCode != KEYCODE_ENTER) { - mJustAddedAutoSpace = false; - } - if (isWordSeparator(primaryCode)) { - handleSeparator(primaryCode); - } else { - handleCharacter(primaryCode, keyCodes); - } - // Cancel the just reverted state - mJustRevertedSeparator = null; - } - if (mKeyboardSwitcher.onKey(primaryCode)) { - changeKeyboardMode(); - } - } - - public void onText(CharSequence text) { - if (VOICE_INSTALLED && mVoiceInputHighlighted) { - commitVoiceInput(); - } - InputConnection ic = getCurrentInputConnection(); - if (ic == null) return; - ic.beginBatchEdit(); - if (mPredicting) { - commitTyped(ic); - } - maybeRemovePreviousPeriod(text); - ic.commitText(text, 1); - ic.endBatchEdit(); - updateShiftKeyState(getCurrentInputEditorInfo()); - mJustRevertedSeparator = null; - mJustAddedAutoSpace = false; - } - - private void handleBackspace() { - if (VOICE_INSTALLED && mVoiceInputHighlighted) { - revertVoiceInput(); - return; - } - boolean deleteChar = false; - InputConnection ic = getCurrentInputConnection(); - if (ic == null) return; - if (mPredicting) { - final int length = mComposing.length(); - if (length > 0) { - mComposing.delete(length - 1, length); - mWord.deleteLast(); - ic.setComposingText(mComposing, 1); - if (mComposing.length() == 0) { - mPredicting = false; - } - postUpdateSuggestions(); - } else { - ic.deleteSurroundingText(1, 0); - } - } else { - deleteChar = true; - } - postUpdateShiftKeyState(); - TextEntryState.backspace(); - if (TextEntryState.getState() == TextEntryState.STATE_UNDO_COMMIT) { - revertLastWord(deleteChar); - return; - } else if (deleteChar) { - sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); - if (mDeleteCount > DELETE_ACCELERATE_AT) { - sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); - } - } - mJustRevertedSeparator = null; - } - - private void handleShift() { - mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE); - if (mKeyboardSwitcher.isAlphabetMode()) { - // Alphabet keyboard - checkToggleCapsLock(); - mInputView.setShifted(mCapsLock || !mInputView.isShifted()); - } else { - mKeyboardSwitcher.toggleShift(); - } - } - - private void handleCharacter(int primaryCode, int[] keyCodes) { - if (VOICE_INSTALLED && mVoiceInputHighlighted) { - commitVoiceInput(); - } - if (isAlphabet(primaryCode) && isPredictionOn() && !isCursorTouchingWord()) { - if (!mPredicting) { - mPredicting = true; - mComposing.setLength(0); - mWord.reset(); - } - } - if (mInputView.isShifted()) { - // TODO: This doesn't work with ß, need to fix it in the next release. - if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT - || keyCodes[0] > Character.MAX_CODE_POINT) { - return; - } - primaryCode = new String(keyCodes, 0, 1).toUpperCase().charAt(0); - } - if (mPredicting) { - if (mInputView.isShifted() && mComposing.length() == 0) { - mWord.setCapitalized(true); - } - mComposing.append((char) primaryCode); - mWord.add(primaryCode, keyCodes); - InputConnection ic = getCurrentInputConnection(); - if (ic != null) { - // If it's the first letter, make note of auto-caps state - if (mWord.size() == 1) { - mWord.setAutoCapitalized( - getCursorCapsMode(ic, getCurrentInputEditorInfo()) != 0); - } - ic.setComposingText(mComposing, 1); - } - postUpdateSuggestions(); - } else { - sendKeyChar((char)primaryCode); - } - updateShiftKeyState(getCurrentInputEditorInfo()); - measureCps(); - TextEntryState.typedCharacter((char) primaryCode, isWordSeparator(primaryCode)); - } - - private void handleSeparator(int primaryCode) { - if (VOICE_INSTALLED && mVoiceInputHighlighted) { - commitVoiceInput(); - } - boolean pickedDefault = false; - // Handle separator - InputConnection ic = getCurrentInputConnection(); - if (ic != null) { - ic.beginBatchEdit(); - } - if (mPredicting) { - // In certain languages where single quote is a separator, it's better - // not to auto correct, but accept the typed word. For instance, - // in Italian dov' should not be expanded to dove' because the elision - // requires the last vowel to be removed. - if (mAutoCorrectOn && primaryCode != '\'' && - (mJustRevertedSeparator == null - || mJustRevertedSeparator.length() == 0 - || mJustRevertedSeparator.charAt(0) != primaryCode)) { - pickDefaultSuggestion(); - pickedDefault = true; - // Picked the suggestion by the space key. We consider this - // as "added an auto space". - if (primaryCode == KEYCODE_SPACE) { - mJustAddedAutoSpace = true; - } - } else { - commitTyped(ic); - } - } - if (mJustAddedAutoSpace && primaryCode == KEYCODE_ENTER) { - removeTrailingSpace(); - mJustAddedAutoSpace = false; - } - sendKeyChar((char)primaryCode); - - // Handle the case of ". ." -> " .." with auto-space if necessary - // before changing the TextEntryState. - if (TextEntryState.getState() == TextEntryState.STATE_PUNCTUATION_AFTER_ACCEPTED - && primaryCode == KEYCODE_PERIOD) { - reswapPeriodAndSpace(); - } - - TextEntryState.typedCharacter((char) primaryCode, true); - if (TextEntryState.getState() == TextEntryState.STATE_PUNCTUATION_AFTER_ACCEPTED - && primaryCode != KEYCODE_ENTER) { - swapPunctuationAndSpace(); - } else if (isPredictionOn() && primaryCode == KEYCODE_SPACE) { - //else if (TextEntryState.STATE_SPACE_AFTER_ACCEPTED) { - doubleSpace(); - } - if (pickedDefault && mBestWord != null) { - TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord); - } - updateShiftKeyState(getCurrentInputEditorInfo()); - if (ic != null) { - ic.endBatchEdit(); - } - } - - private void handleClose() { - commitTyped(getCurrentInputConnection()); - if (VOICE_INSTALLED & mRecognizing) { - mVoiceInput.cancel(); - } - requestHideSelf(0); - mInputView.closing(); - TextEntryState.endSession(); - } - - private void checkToggleCapsLock() { - if (mInputView.getKeyboard().isShifted()) { - toggleCapsLock(); - } - } - - private void toggleCapsLock() { - mCapsLock = !mCapsLock; - if (mKeyboardSwitcher.isAlphabetMode()) { - ((LatinKeyboard) mInputView.getKeyboard()).setShiftLocked(mCapsLock); - } - } - - private void postUpdateSuggestions() { - mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS); - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SUGGESTIONS), 100); - } - - private boolean isPredictionOn() { - boolean predictionOn = mPredictionOn; - return predictionOn; - } - - private boolean isCandidateStripVisible() { - return isPredictionOn() && mShowSuggestions; - } - - public void onCancelVoice() { - if (mRecognizing) { - switchToKeyboardView(); - } - } - - private void switchToKeyboardView() { - mHandler.post(new Runnable() { - public void run() { - mRecognizing = false; - if (mInputView != null) { - setInputView(mInputView); - } - updateInputViewShown(); - }}); - } - - private void switchToRecognitionStatusView() { - final boolean configChanged = mConfigurationChanging; - mHandler.post(new Runnable() { - public void run() { - mRecognizing = true; - View v = mVoiceInput.getView(); - ViewParent p = v.getParent(); - if (p != null && p instanceof ViewGroup) { - ((ViewGroup)v.getParent()).removeView(v); - } - setInputView(v); - updateInputViewShown(); - if (configChanged) { - mVoiceInput.onConfigurationChanged(); - } - }}); - } - - private void startListening(boolean swipe) { - if (!mHasUsedVoiceInput || - (!mLocaleSupportedForVoiceInput && !mHasUsedVoiceInputUnsupportedLocale)) { - // Calls reallyStartListening if user clicks OK, does nothing if user clicks Cancel. - showVoiceWarningDialog(swipe); - } else { - reallyStartListening(swipe); - } - } - - private void reallyStartListening(boolean swipe) { - if (!mHasUsedVoiceInput) { - // The user has started a voice input, so remember that in the - // future (so we don't show the warning dialog after the first run). - SharedPreferences.Editor editor = - PreferenceManager.getDefaultSharedPreferences(this).edit(); - editor.putBoolean(PREF_HAS_USED_VOICE_INPUT, true); - editor.commit(); - mHasUsedVoiceInput = true; - } - - if (!mLocaleSupportedForVoiceInput && !mHasUsedVoiceInputUnsupportedLocale) { - // The user has started a voice input from an unsupported locale, so remember that - // in the future (so we don't show the warning dialog the next time they do this). - SharedPreferences.Editor editor = - PreferenceManager.getDefaultSharedPreferences(this).edit(); - editor.putBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, true); - editor.commit(); - mHasUsedVoiceInputUnsupportedLocale = true; - } - - // Clear N-best suggestions - setSuggestions(null, false, false, true); - - FieldContext context = new FieldContext( - getCurrentInputConnection(), - getCurrentInputEditorInfo(), - mLanguageSwitcher.getInputLanguage(), - mLanguageSwitcher.getEnabledLanguages()); - mVoiceInput.startListening(context, swipe); - switchToRecognitionStatusView(); - } - - private void showVoiceWarningDialog(final boolean swipe) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setCancelable(true); - builder.setIcon(R.drawable.ic_mic_dialog); - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - mVoiceInput.logKeyboardWarningDialogOk(); - reallyStartListening(swipe); - } - }); - builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - mVoiceInput.logKeyboardWarningDialogCancel(); - } - }); - - if (mLocaleSupportedForVoiceInput) { - String message = getString(R.string.voice_warning_may_not_understand) + "\n\n" + - getString(R.string.voice_warning_how_to_turn_off); - builder.setMessage(message); - } else { - String message = getString(R.string.voice_warning_locale_not_supported) + "\n\n" + - getString(R.string.voice_warning_may_not_understand) + "\n\n" + - getString(R.string.voice_warning_how_to_turn_off); - builder.setMessage(message); - } - - builder.setTitle(R.string.voice_warning_title); - mVoiceWarningDialog = builder.create(); - - Window window = mVoiceWarningDialog.getWindow(); - WindowManager.LayoutParams lp = window.getAttributes(); - lp.token = mInputView.getWindowToken(); - lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; - window.setAttributes(lp); - window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - mVoiceInput.logKeyboardWarningDialogShown(); - mVoiceWarningDialog.show(); - } - - public void onVoiceResults(List<String> candidates, - Map<String, List<CharSequence>> alternatives) { - if (!mRecognizing) { - return; - } - mVoiceResults.candidates = candidates; - mVoiceResults.alternatives = alternatives; - mHandler.sendMessage(mHandler.obtainMessage(MSG_VOICE_RESULTS)); - } - - private void handleVoiceResults() { - mAfterVoiceInput = true; - mImmediatelyAfterVoiceInput = true; - - InputConnection ic = getCurrentInputConnection(); - if (!isFullscreenMode()) { - // Start listening for updates to the text from typing, etc. - if (ic != null) { - ExtractedTextRequest req = new ExtractedTextRequest(); - ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR); - } - } - - vibrate(); - switchToKeyboardView(); - - final List<CharSequence> nBest = new ArrayList<CharSequence>(); - boolean capitalizeFirstWord = preferCapitalization() - || (mKeyboardSwitcher.isAlphabetMode() && mInputView.isShifted()); - for (String c : mVoiceResults.candidates) { - if (capitalizeFirstWord) { - c = Character.toUpperCase(c.charAt(0)) + c.substring(1, c.length()); - } - nBest.add(c); - } - - if (nBest.size() == 0) { - return; - } - - String bestResult = nBest.get(0).toString(); - - mVoiceInput.logVoiceInputDelivered(); - - mHints.registerVoiceResult(bestResult); - - if (ic != null) ic.beginBatchEdit(); // To avoid extra updates on committing older text - - commitTyped(ic); - EditingUtil.appendText(ic, bestResult); - - if (ic != null) ic.endBatchEdit(); - - // Show N-Best alternates, if there is more than one choice. - if (nBest.size() > 1) { - mImmediatelyAfterVoiceSuggestions = true; - mShowingVoiceSuggestions = true; - setSuggestions(nBest.subList(1, nBest.size()), false, true, true); - setCandidatesViewShown(true); - } - mVoiceInputHighlighted = true; - mWordToSuggestions.putAll(mVoiceResults.alternatives); - - } - - private void setSuggestions( - List<CharSequence> suggestions, - boolean completions, - - boolean typedWordValid, - boolean haveMinimalSuggestion) { - - if (mIsShowingHint) { - setCandidatesView(mCandidateViewContainer); - mIsShowingHint = false; - } - - if (mCandidateView != null) { - mCandidateView.setSuggestions( - suggestions, completions, typedWordValid, haveMinimalSuggestion); - } - } - - private void updateSuggestions() { - mSuggestionShouldReplaceCurrentWord = false; - - ((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(null); - - // Check if we have a suggestion engine attached. - if ((mSuggest == null || !isPredictionOn()) && !mVoiceInputHighlighted) { - return; - } - - if (!mPredicting) { - setNextSuggestions(); - return; - } - - List<CharSequence> stringList = mSuggest.getSuggestions(mInputView, mWord, false); - int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies(); - - ((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(nextLettersFrequencies); - - boolean correctionAvailable = mSuggest.hasMinimalCorrection(); - //|| mCorrectionMode == mSuggest.CORRECTION_FULL; - CharSequence typedWord = mWord.getTypedWord(); - // If we're in basic correct - boolean typedWordValid = mSuggest.isValidWord(typedWord) || - (preferCapitalization() && mSuggest.isValidWord(typedWord.toString().toLowerCase())); - if (mCorrectionMode == Suggest.CORRECTION_FULL) { - correctionAvailable |= typedWordValid; - } - // Don't auto-correct words with multiple capital letter - correctionAvailable &= !mWord.isMostlyCaps(); - - setSuggestions(stringList, false, typedWordValid, correctionAvailable); - if (stringList.size() > 0) { - if (correctionAvailable && !typedWordValid && stringList.size() > 1) { - mBestWord = stringList.get(1); - } else { - mBestWord = typedWord; - } - } else { - mBestWord = null; - } - setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn); - } - - private void pickDefaultSuggestion() { - // Complete any pending candidate query first - if (mHandler.hasMessages(MSG_UPDATE_SUGGESTIONS)) { - mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS); - updateSuggestions(); - } - if (mBestWord != null) { - TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord); - mJustAccepted = true; - pickSuggestion(mBestWord); - // Add the word to the auto dictionary if it's not a known word - checkAddToDictionary(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED); - } - } - - public void pickSuggestionManually(int index, CharSequence suggestion) { - if (mAfterVoiceInput && mShowingVoiceSuggestions) mVoiceInput.logNBestChoose(index); - - InputConnection ic = getCurrentInputConnection(); - if (ic != null) { - ic.beginBatchEdit(); - } - if (mCompletionOn && mCompletions != null && index >= 0 - && index < mCompletions.length) { - CompletionInfo ci = mCompletions[index]; - if (ic != null) { - ic.commitCompletion(ci); - } - mCommittedLength = suggestion.length(); - if (mCandidateView != null) { - mCandidateView.clear(); - } - updateShiftKeyState(getCurrentInputEditorInfo()); - if (ic != null) { - ic.endBatchEdit(); - } - return; - } - - // If this is a punctuation, apply it through the normal key press - if (suggestion.length() == 1 && isWordSeparator(suggestion.charAt(0))) { - onKey(suggestion.charAt(0), null); - if (ic != null) { - ic.endBatchEdit(); - } - return; - } - mJustAccepted = true; - pickSuggestion(suggestion); - // Add the word to the auto dictionary if it's not a known word - checkAddToDictionary(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED); - TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion); - // Follow it with a space - if (mAutoSpace) { - sendSpace(); - mJustAddedAutoSpace = true; - } - // Fool the state watcher so that a subsequent backspace will not do a revert - TextEntryState.typedCharacter((char) KEYCODE_SPACE, true); - if (index == 0 && mCorrectionMode > 0 && !mSuggest.isValidWord(suggestion)) { - mCandidateView.showAddToDictionaryHint(suggestion); - } - if (ic != null) { - ic.endBatchEdit(); - } - } - - private void pickSuggestion(CharSequence suggestion) { - if (mCapsLock) { - suggestion = suggestion.toString().toUpperCase(); - } else if (preferCapitalization() - || (mKeyboardSwitcher.isAlphabetMode() && mInputView.isShifted())) { - suggestion = suggestion.toString().toUpperCase().charAt(0) - + suggestion.subSequence(1, suggestion.length()).toString(); - } - InputConnection ic = getCurrentInputConnection(); - if (ic != null) { - if (mSuggestionShouldReplaceCurrentWord) { - EditingUtil.deleteWordAtCursor(ic, getWordSeparators()); - } - if (!VoiceInput.DELETE_SYMBOL.equals(suggestion)) { - ic.commitText(suggestion, 1); - } - } - mPredicting = false; - mCommittedLength = suggestion.length(); - ((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(null); - setNextSuggestions(); - updateShiftKeyState(getCurrentInputEditorInfo()); - } - - private void setNextSuggestions() { - setSuggestions(mSuggestPuncList, false, false, false); - } - - private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta) { - if (mAutoDictionary.isValidWord(suggestion) - || !mSuggest.isValidWord(suggestion.toString().toLowerCase())) { - mAutoDictionary.addWord(suggestion.toString(), frequencyDelta); - } - } - - private boolean isCursorTouchingWord() { - InputConnection ic = getCurrentInputConnection(); - if (ic == null) return false; - CharSequence toLeft = ic.getTextBeforeCursor(1, 0); - CharSequence toRight = ic.getTextAfterCursor(1, 0); - if (!TextUtils.isEmpty(toLeft) - && !isWordSeparator(toLeft.charAt(0))) { - return true; - } - if (!TextUtils.isEmpty(toRight) - && !isWordSeparator(toRight.charAt(0))) { - return true; - } - return false; - } - - public void revertLastWord(boolean deleteChar) { - final int length = mComposing.length(); - if (!mPredicting && length > 0) { - final InputConnection ic = getCurrentInputConnection(); - mPredicting = true; - ic.beginBatchEdit(); - mJustRevertedSeparator = ic.getTextBeforeCursor(1, 0); - if (deleteChar) ic.deleteSurroundingText(1, 0); - int toDelete = mCommittedLength; - CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0); - if (toTheLeft != null && toTheLeft.length() > 0 - && isWordSeparator(toTheLeft.charAt(0))) { - toDelete--; - } - ic.deleteSurroundingText(toDelete, 0); - ic.setComposingText(mComposing, 1); - TextEntryState.backspace(); - ic.endBatchEdit(); - postUpdateSuggestions(); - } else { - sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); - mJustRevertedSeparator = null; - } - } - - protected String getWordSeparators() { - return mWordSeparators; - } - - public boolean isWordSeparator(int code) { - String separators = getWordSeparators(); - return separators.contains(String.valueOf((char)code)); - } - - public boolean isSentenceSeparator(int code) { - return mSentenceSeparators.contains(String.valueOf((char)code)); - } - - private void sendSpace() { - sendKeyChar((char)KEYCODE_SPACE); - updateShiftKeyState(getCurrentInputEditorInfo()); - //onKey(KEY_SPACE[0], KEY_SPACE); - } - - public boolean preferCapitalization() { - return mWord.isCapitalized(); - } - - public void swipeRight() { - if (userHasNotTypedRecently() && VOICE_INSTALLED && mEnableVoice && - fieldCanDoVoice(makeFieldContext())) { - startListening(true /* was a swipe */); - } - - if (LatinKeyboardView.DEBUG_AUTO_PLAY) { - ClipboardManager cm = ((ClipboardManager)getSystemService(CLIPBOARD_SERVICE)); - CharSequence text = cm.getText(); - if (!TextUtils.isEmpty(text)) { - mInputView.startPlaying(text.toString()); - } - } - } - - private void toggleLanguage(boolean reset, boolean next) { - if (reset) { - mLanguageSwitcher.reset(); - } else { - if (next) { - mLanguageSwitcher.next(); - } else { - mLanguageSwitcher.prev(); - } - } - int currentKeyboardMode = mKeyboardSwitcher.getKeyboardMode(); - reloadKeyboards(); - mKeyboardSwitcher.makeKeyboards(true); - mKeyboardSwitcher.setKeyboardMode(currentKeyboardMode, 0, - mEnableVoiceButton && mEnableVoice); - initSuggest(mLanguageSwitcher.getInputLanguage()); - mLanguageSwitcher.persist(); - updateShiftKeyState(getCurrentInputEditorInfo()); - } - - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, - String key) { - if (PREF_SELECTED_LANGUAGES.equals(key)) { - mLanguageSwitcher.loadLocales(sharedPreferences); - mRefreshKeyboardRequired = true; - } - } - - public void swipeLeft() { - } - - public void swipeDown() { - handleClose(); - } - - public void swipeUp() { - //launchSettings(); - } - - public void onPress(int primaryCode) { - vibrate(); - playKeyClick(primaryCode); - } - - public void onRelease(int primaryCode) { - // Reset any drag flags in the keyboard - ((LatinKeyboard) mInputView.getKeyboard()).keyReleased(); - //vibrate(); - } - - private FieldContext makeFieldContext() { - return new FieldContext( - getCurrentInputConnection(), - getCurrentInputEditorInfo(), - mLanguageSwitcher.getInputLanguage(), - mLanguageSwitcher.getEnabledLanguages()); - } - - private boolean fieldCanDoVoice(FieldContext fieldContext) { - return !mPasswordText - && mVoiceInput != null - && !mVoiceInput.isBlacklistedField(fieldContext); - } - - private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo attribute) { - return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext) - && !(attribute != null && attribute.privateImeOptions != null - && attribute.privateImeOptions.equals(IME_OPTION_NO_MICROPHONE)) - && RecognitionManager.isRecognitionAvailable(this); - } - - // receive ringer mode changes to detect silent mode - private BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - updateRingerMode(); - } - }; - - // update flags for silent mode - private void updateRingerMode() { - if (mAudioManager == null) { - mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - } - if (mAudioManager != null) { - mSilentMode = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL); - } - } - - private boolean userHasNotTypedRecently() { - return (SystemClock.uptimeMillis() - mLastKeyTime) - > MIN_MILLIS_AFTER_TYPING_BEFORE_SWIPE; - } - - private void playKeyClick(int primaryCode) { - // if mAudioManager is null, we don't have the ringer state yet - // mAudioManager will be set by updateRingerMode - if (mAudioManager == null) { - if (mInputView != null) { - updateRingerMode(); - } - } - if (mSoundOn && !mSilentMode) { - // FIXME: Volume and enable should come from UI settings - // FIXME: These should be triggered after auto-repeat logic - int sound = AudioManager.FX_KEYPRESS_STANDARD; - switch (primaryCode) { - case Keyboard.KEYCODE_DELETE: - sound = AudioManager.FX_KEYPRESS_DELETE; - break; - case KEYCODE_ENTER: - sound = AudioManager.FX_KEYPRESS_RETURN; - break; - case KEYCODE_SPACE: - sound = AudioManager.FX_KEYPRESS_SPACEBAR; - break; - } - mAudioManager.playSoundEffect(sound, FX_VOLUME); - } - } - - private void vibrate() { - if (!mVibrateOn) { - return; - } - if (mInputView != null) { - mInputView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, - HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } - } - - private void checkTutorial(String privateImeOptions) { - if (privateImeOptions == null) return; - if (privateImeOptions.equals("com.android.setupwizard:ShowTutorial")) { - if (mTutorial == null) startTutorial(); - } else if (privateImeOptions.equals("com.android.setupwizard:HideTutorial")) { - if (mTutorial != null) { - if (mTutorial.close()) { - mTutorial = null; - } - } - } - } - - private void startTutorial() { - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_TUTORIAL), 500); - } - - void tutorialDone() { - mTutorial = null; - } - - void promoteToUserDictionary(String word, int frequency) { - if (mUserDictionary.isValidWord(word)) return; - mUserDictionary.addWord(word, frequency); - } - - WordComposer getCurrentWord() { - return mWord; - } - - private void updateCorrectionMode() { - mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false; - mAutoCorrectOn = (mAutoCorrectEnabled || mQuickFixes) - && !mInputTypeNoAutoCorrect && mHasDictionary; - mCorrectionMode = (mAutoCorrectOn && mAutoCorrectEnabled) - ? Suggest.CORRECTION_FULL - : (mAutoCorrectOn ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE); - if (mSuggest != null) { - mSuggest.setCorrectionMode(mCorrectionMode); - } - } - - private void updateAutoTextEnabled(Locale systemLocale) { - if (mSuggest == null) return; - boolean different = !systemLocale.getLanguage().equalsIgnoreCase(mLocale.substring(0, 2)); - mSuggest.setAutoTextEnabled(!different && mQuickFixes); - } - - protected void launchSettings() { - launchSettings(LatinIMESettings.class); - } - - protected void launchSettings(Class settingsClass) { - handleClose(); - Intent intent = new Intent(); - intent.setClass(LatinIME.this, settingsClass); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - } - - private void loadSettings() { - // Get the settings preferences - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - mVibrateOn = sp.getBoolean(PREF_VIBRATE_ON, false); - mSoundOn = sp.getBoolean(PREF_SOUND_ON, false); - mAutoCap = sp.getBoolean(PREF_AUTO_CAP, true); - mQuickFixes = sp.getBoolean(PREF_QUICK_FIXES, true); - mHasUsedVoiceInput = sp.getBoolean(PREF_HAS_USED_VOICE_INPUT, false); - mHasUsedVoiceInputUnsupportedLocale = - sp.getBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, false); - - // Get the current list of supported locales and check the current locale against that - // list. We cache this value so as not to check it every time the user starts a voice - // input. Because this method is called by onStartInputView, this should mean that as - // long as the locale doesn't change while the user is keeping the IME open, the - // value should never be stale. - String supportedLocalesString = SettingsUtil.getSettingsString( - getContentResolver(), - SettingsUtil.LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES, - DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES); - ArrayList<String> voiceInputSupportedLocales = - newArrayList(supportedLocalesString.split("\\s+")); - - mLocaleSupportedForVoiceInput = voiceInputSupportedLocales.contains(mLocale); - - mShowSuggestions = sp.getBoolean(PREF_SHOW_SUGGESTIONS, true); - - if (VOICE_INSTALLED) { - final String voiceMode = sp.getString(PREF_VOICE_MODE, - getString(R.string.voice_mode_main)); - boolean enableVoice = !voiceMode.equals(getString(R.string.voice_mode_off)) - && mEnableVoiceButton; - boolean voiceOnPrimary = voiceMode.equals(getString(R.string.voice_mode_main)); - if (mKeyboardSwitcher != null && - (enableVoice != mEnableVoice || voiceOnPrimary != mVoiceOnPrimary)) { - mKeyboardSwitcher.setVoiceMode(enableVoice, voiceOnPrimary); - } - mEnableVoice = enableVoice; - mVoiceOnPrimary = voiceOnPrimary; - } - mAutoCorrectEnabled = sp.getBoolean(PREF_AUTO_COMPLETE, - mResources.getBoolean(R.bool.enable_autocorrect)) & mShowSuggestions; - updateCorrectionMode(); - updateAutoTextEnabled(mResources.getConfiguration().locale); - mLanguageSwitcher.loadLocales(sp); - } - - private void initSuggestPuncList() { - mSuggestPuncList = new ArrayList<CharSequence>(); - String suggestPuncs = mResources.getString(R.string.suggested_punctuations); - if (suggestPuncs != null) { - for (int i = 0; i < suggestPuncs.length(); i++) { - mSuggestPuncList.add(suggestPuncs.subSequence(i, i + 1)); - } - } - } - - private void showOptionsMenu() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setCancelable(true); - builder.setIcon(R.drawable.ic_dialog_keyboard); - builder.setNegativeButton(android.R.string.cancel, null); - CharSequence itemSettings = getString(R.string.english_ime_settings); - CharSequence itemInputMethod = getString(R.string.inputMethod); - builder.setItems(new CharSequence[] { - itemSettings, itemInputMethod}, - new DialogInterface.OnClickListener() { - - public void onClick(DialogInterface di, int position) { - di.dismiss(); - switch (position) { - case POS_SETTINGS: - launchSettings(); - break; - case POS_METHOD: - ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)) - .showInputMethodPicker(); - break; - } - } - }); - builder.setTitle(mResources.getString(R.string.english_ime_name)); - mOptionsDialog = builder.create(); - Window window = mOptionsDialog.getWindow(); - WindowManager.LayoutParams lp = window.getAttributes(); - lp.token = mInputView.getWindowToken(); - lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; - window.setAttributes(lp); - window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - mOptionsDialog.show(); - } - - private void changeKeyboardMode() { - mKeyboardSwitcher.toggleSymbols(); - if (mCapsLock && mKeyboardSwitcher.isAlphabetMode()) { - ((LatinKeyboard) mInputView.getKeyboard()).setShiftLocked(mCapsLock); - } - - updateShiftKeyState(getCurrentInputEditorInfo()); - } - - public static <E> ArrayList<E> newArrayList(E... elements) { - int capacity = (elements.length * 110) / 100 + 5; - ArrayList<E> list = new ArrayList<E>(capacity); - Collections.addAll(list, elements); - return list; - } - - @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { - super.dump(fd, fout, args); - - final Printer p = new PrintWriterPrinter(fout); - p.println("LatinIME state :"); - p.println(" Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode()); - p.println(" mCapsLock=" + mCapsLock); - p.println(" mComposing=" + mComposing.toString()); - p.println(" mPredictionOn=" + mPredictionOn); - p.println(" mCorrectionMode=" + mCorrectionMode); - p.println(" mPredicting=" + mPredicting); - p.println(" mAutoCorrectOn=" + mAutoCorrectOn); - p.println(" mAutoSpace=" + mAutoSpace); - p.println(" mCompletionOn=" + mCompletionOn); - p.println(" TextEntryState.state=" + TextEntryState.getState()); - p.println(" mSoundOn=" + mSoundOn); - p.println(" mVibrateOn=" + mVibrateOn); - } - - // Characters per second measurement - - private static final boolean PERF_DEBUG = false; - private long mLastCpsTime; - private static final int CPS_BUFFER_SIZE = 16; - private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE]; - private int mCpsIndex; - private boolean mInputTypeNoAutoCorrect; - - private void measureCps() { - if (!LatinIME.PERF_DEBUG) return; - long now = System.currentTimeMillis(); - if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial - mCpsIntervals[mCpsIndex] = now - mLastCpsTime; - mLastCpsTime = now; - mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE; - long total = 0; - for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i]; - System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total)); - } - -} diff --git a/src/com/android/inputmethod/latin/LatinIMEBackupAgent.java b/src/com/android/inputmethod/latin/LatinIMEBackupAgent.java deleted file mode 100644 index 62da86cd4..000000000 --- a/src/com/android/inputmethod/latin/LatinIMEBackupAgent.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import android.app.backup.BackupHelperAgent; -import android.app.backup.SharedPreferencesBackupHelper; - -/** - * Backs up the Latin IME shared preferences. - */ -public class LatinIMEBackupAgent extends BackupHelperAgent { - - public void onCreate() { - addHelper("shared_pref", new SharedPreferencesBackupHelper(this, - getPackageName() + "_preferences")); - } -} diff --git a/src/com/android/inputmethod/latin/LatinIMESettings.java b/src/com/android/inputmethod/latin/LatinIMESettings.java deleted file mode 100644 index f76ec99b6..000000000 --- a/src/com/android/inputmethod/latin/LatinIMESettings.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import java.util.ArrayList; -import java.util.Locale; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.backup.BackupManager; -import android.content.DialogInterface; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceActivity; -import android.preference.PreferenceGroup; -import android.preference.Preference.OnPreferenceClickListener; -import android.speech.RecognitionManager; -import android.text.AutoText; -import android.util.Log; - -import com.android.inputmethod.voice.SettingsUtil; -import com.android.inputmethod.voice.VoiceInputLogger; - -public class LatinIMESettings extends PreferenceActivity - implements SharedPreferences.OnSharedPreferenceChangeListener, - DialogInterface.OnDismissListener { - - private static final String QUICK_FIXES_KEY = "quick_fixes"; - private static final String SHOW_SUGGESTIONS_KEY = "show_suggestions"; - private static final String PREDICTION_SETTINGS_KEY = "prediction_settings"; - private static final String VOICE_SETTINGS_KEY = "voice_mode"; - private static final String VOICE_ON_PRIMARY_KEY = "voice_on_main"; - private static final String VOICE_SERVER_KEY = "voice_server_url"; - - private static final String TAG = "LatinIMESettings"; - - // Dialog ids - private static final int VOICE_INPUT_CONFIRM_DIALOG = 0; - - private CheckBoxPreference mQuickFixes; - private CheckBoxPreference mShowSuggestions; - private ListPreference mVoicePreference; - private boolean mVoiceOn; - - private VoiceInputLogger mLogger; - - private boolean mOkClicked = false; - private String mVoiceModeOff; - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - addPreferencesFromResource(R.xml.prefs); - mQuickFixes = (CheckBoxPreference) findPreference(QUICK_FIXES_KEY); - mShowSuggestions = (CheckBoxPreference) findPreference(SHOW_SUGGESTIONS_KEY); - mVoicePreference = (ListPreference) findPreference(VOICE_SETTINGS_KEY); - SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); - prefs.registerOnSharedPreferenceChangeListener(this); - - mVoiceModeOff = getString(R.string.voice_mode_off); - mVoiceOn = !(prefs.getString(VOICE_SETTINGS_KEY, mVoiceModeOff).equals(mVoiceModeOff)); - mLogger = VoiceInputLogger.getLogger(this); - } - - @Override - protected void onResume() { - super.onResume(); - int autoTextSize = AutoText.getSize(getListView()); - if (autoTextSize < 1) { - ((PreferenceGroup) findPreference(PREDICTION_SETTINGS_KEY)) - .removePreference(mQuickFixes); - } - if (!LatinIME.VOICE_INSTALLED - || !RecognitionManager.isRecognitionAvailable(this)) { - getPreferenceScreen().removePreference(mVoicePreference); - } else { - updateVoiceModeSummary(); - } - } - - @Override - protected void onDestroy() { - getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener( - this); - super.onDestroy(); - } - - public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { - (new BackupManager(this)).dataChanged(); - // If turning on voice input, show dialog - if (key.equals(VOICE_SETTINGS_KEY) && !mVoiceOn) { - if (! prefs.getString(VOICE_SETTINGS_KEY, mVoiceModeOff) - .equals(mVoiceModeOff)) { - showVoiceConfirmation(); - } - } - mVoiceOn = !(prefs.getString(VOICE_SETTINGS_KEY, mVoiceModeOff).equals(mVoiceModeOff)); - updateVoiceModeSummary(); - } - - private void showVoiceConfirmation() { - mOkClicked = false; - showDialog(VOICE_INPUT_CONFIRM_DIALOG); - } - - private void updateVoiceModeSummary() { - mVoicePreference.setSummary( - getResources().getStringArray(R.array.voice_input_modes_summary) - [mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]); - } - - @Override - protected Dialog onCreateDialog(int id) { - switch (id) { - case VOICE_INPUT_CONFIRM_DIALOG: - DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - if (whichButton == DialogInterface.BUTTON_NEGATIVE) { - mVoicePreference.setValue(mVoiceModeOff); - mLogger.settingsWarningDialogCancel(); - } else if (whichButton == DialogInterface.BUTTON_POSITIVE) { - mOkClicked = true; - mLogger.settingsWarningDialogOk(); - } - updateVoicePreference(); - } - }; - AlertDialog.Builder builder = new AlertDialog.Builder(this) - .setTitle(R.string.voice_warning_title) - .setPositiveButton(android.R.string.ok, listener) - .setNegativeButton(android.R.string.cancel, listener); - - // Get the current list of supported locales and check the current locale against - // that list, to decide whether to put a warning that voice input will not work in - // the current language as part of the pop-up confirmation dialog. - String supportedLocalesString = SettingsUtil.getSettingsString( - getContentResolver(), - SettingsUtil.LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES, - LatinIME.DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES); - ArrayList<String> voiceInputSupportedLocales = - LatinIME.newArrayList(supportedLocalesString.split("\\s+")); - boolean localeSupported = voiceInputSupportedLocales.contains( - Locale.getDefault().toString()); - - if (localeSupported) { - String message = getString(R.string.voice_warning_may_not_understand) + "\n\n" + - getString(R.string.voice_hint_dialog_message); - builder.setMessage(message); - } else { - String message = getString(R.string.voice_warning_locale_not_supported) + - "\n\n" + getString(R.string.voice_warning_may_not_understand) + "\n\n" + - getString(R.string.voice_hint_dialog_message); - builder.setMessage(message); - } - - AlertDialog dialog = builder.create(); - dialog.setOnDismissListener(this); - mLogger.settingsWarningDialogShown(); - return dialog; - default: - Log.e(TAG, "unknown dialog " + id); - return null; - } - } - - public void onDismiss(DialogInterface dialog) { - mLogger.settingsWarningDialogDismissed(); - if (!mOkClicked) { - // This assumes that onPreferenceClick gets called first, and this if the user - // agreed after the warning, we set the mOkClicked value to true. - mVoicePreference.setValue(mVoiceModeOff); - } - } - - private void updateVoicePreference() { - boolean isChecked = !mVoicePreference.getValue().equals(mVoiceModeOff); - if (isChecked) { - mLogger.voiceInputSettingEnabled(); - } else { - mLogger.voiceInputSettingDisabled(); - } - } -} diff --git a/src/com/android/inputmethod/latin/LatinKeyboard.java b/src/com/android/inputmethod/latin/LatinKeyboard.java deleted file mode 100644 index 58e1dc767..000000000 --- a/src/com/android/inputmethod/latin/LatinKeyboard.java +++ /dev/null @@ -1,762 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import java.util.List; -import java.util.Locale; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.PorterDuff; -import android.graphics.Rect; -import android.graphics.Paint.Align; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.inputmethodservice.Keyboard; -import android.text.TextPaint; -import android.util.Log; -import android.view.ViewConfiguration; -import android.view.inputmethod.EditorInfo; - -public class LatinKeyboard extends Keyboard { - - private static final boolean DEBUG_PREFERRED_LETTER = false; - private static final String TAG = "LatinKeyboard"; - - private Drawable mShiftLockIcon; - private Drawable mShiftLockPreviewIcon; - private Drawable mOldShiftIcon; - private Drawable mOldShiftPreviewIcon; - private Drawable mSpaceIcon; - private Drawable mSpacePreviewIcon; - private Drawable mMicIcon; - private Drawable mMicPreviewIcon; - private Drawable m123MicIcon; - private Drawable m123MicPreviewIcon; - private Drawable mButtonArrowLeftIcon; - private Drawable mButtonArrowRightIcon; - private Key mShiftKey; - private Key mEnterKey; - private Key mF1Key; - private Key mSpaceKey; - private Key m123Key; - private int mSpaceKeyIndex = -1; - private int mSpaceDragStartX; - private int mSpaceDragLastDiff; - /* package */ Locale mLocale; - private LanguageSwitcher mLanguageSwitcher; - private Resources mRes; - private Context mContext; - private int mMode; - // Whether this keyboard has voice icon on it - private boolean mHasVoiceButton; - // Whether voice icon is enabled at all - private boolean mVoiceEnabled; - private boolean mIsAlphaKeyboard; - private CharSequence m123Label; - private boolean mCurrentlyInSpace; - private SlidingLocaleDrawable mSlidingLocaleIcon; - private Rect mBounds = new Rect(); - private int[] mPrefLetterFrequencies; - private boolean mPreemptiveCorrection; - private int mPrefLetter; - private int mPrefLetterX; - private int mPrefLetterY; - private int mPrefDistance; - - private int mExtensionResId; - - private static final int SHIFT_OFF = 0; - private static final int SHIFT_ON = 1; - private static final int SHIFT_LOCKED = 2; - - private int mShiftState = SHIFT_OFF; - - private static final float SPACEBAR_DRAG_THRESHOLD = 0.8f; - private static final float OVERLAP_PERCENTAGE_LOW_PROB = 0.70f; - private static final float OVERLAP_PERCENTAGE_HIGH_PROB = 0.85f; - - static int sSpacebarVerticalCorrection; - - public LatinKeyboard(Context context, int xmlLayoutResId) { - this(context, xmlLayoutResId, 0); - } - - public LatinKeyboard(Context context, int xmlLayoutResId, int mode) { - super(context, xmlLayoutResId, mode); - final Resources res = context.getResources(); - mContext = context; - mMode = mode; - mRes = res; - mShiftLockIcon = res.getDrawable(R.drawable.sym_keyboard_shift_locked); - mShiftLockPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_shift_locked); - mShiftLockPreviewIcon.setBounds(0, 0, - mShiftLockPreviewIcon.getIntrinsicWidth(), - mShiftLockPreviewIcon.getIntrinsicHeight()); - mSpaceIcon = res.getDrawable(R.drawable.sym_keyboard_space); - mSpacePreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_space); - mMicIcon = res.getDrawable(R.drawable.sym_keyboard_mic); - mMicPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_mic); - setDefaultBounds(mMicPreviewIcon); - mButtonArrowLeftIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_left); - mButtonArrowRightIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_right); - m123MicIcon = res.getDrawable(R.drawable.sym_keyboard_123_mic); - m123MicPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_123_mic); - setDefaultBounds(m123MicPreviewIcon); - sSpacebarVerticalCorrection = res.getDimensionPixelOffset( - R.dimen.spacebar_vertical_correction); - mIsAlphaKeyboard = xmlLayoutResId == R.xml.kbd_qwerty; - mSpaceKeyIndex = indexOf((int) ' '); - } - - public LatinKeyboard(Context context, int layoutTemplateResId, - CharSequence characters, int columns, int horizontalPadding) { - super(context, layoutTemplateResId, characters, columns, horizontalPadding); - } - - @Override - protected Key createKeyFromXml(Resources res, Row parent, int x, int y, - XmlResourceParser parser) { - Key key = new LatinKey(res, parent, x, y, parser); - switch (key.codes[0]) { - case 10: - mEnterKey = key; - break; - case LatinKeyboardView.KEYCODE_F1: - mF1Key = key; - break; - case 32: - mSpaceKey = key; - break; - case KEYCODE_MODE_CHANGE: - m123Key = key; - m123Label = key.label; - break; - } - return key; - } - - void setImeOptions(Resources res, int mode, int options) { - if (mEnterKey != null) { - // Reset some of the rarely used attributes. - mEnterKey.popupCharacters = null; - mEnterKey.popupResId = 0; - mEnterKey.text = null; - switch (options&(EditorInfo.IME_MASK_ACTION|EditorInfo.IME_FLAG_NO_ENTER_ACTION)) { - case EditorInfo.IME_ACTION_GO: - mEnterKey.iconPreview = null; - mEnterKey.icon = null; - mEnterKey.label = res.getText(R.string.label_go_key); - break; - case EditorInfo.IME_ACTION_NEXT: - mEnterKey.iconPreview = null; - mEnterKey.icon = null; - mEnterKey.label = res.getText(R.string.label_next_key); - break; - case EditorInfo.IME_ACTION_DONE: - mEnterKey.iconPreview = null; - mEnterKey.icon = null; - mEnterKey.label = res.getText(R.string.label_done_key); - break; - case EditorInfo.IME_ACTION_SEARCH: - mEnterKey.iconPreview = res.getDrawable( - R.drawable.sym_keyboard_feedback_search); - mEnterKey.icon = res.getDrawable( - R.drawable.sym_keyboard_search); - mEnterKey.label = null; - break; - case EditorInfo.IME_ACTION_SEND: - mEnterKey.iconPreview = null; - mEnterKey.icon = null; - mEnterKey.label = res.getText(R.string.label_send_key); - break; - default: - if (mode == KeyboardSwitcher.MODE_IM) { - mEnterKey.icon = null; - mEnterKey.iconPreview = null; - mEnterKey.label = ":-)"; - mEnterKey.text = ":-) "; - mEnterKey.popupResId = R.xml.popup_smileys; - } else { - mEnterKey.iconPreview = res.getDrawable( - R.drawable.sym_keyboard_feedback_return); - mEnterKey.icon = res.getDrawable( - R.drawable.sym_keyboard_return); - mEnterKey.label = null; - } - break; - } - // Set the initial size of the preview icon - if (mEnterKey.iconPreview != null) { - mEnterKey.iconPreview.setBounds(0, 0, - mEnterKey.iconPreview.getIntrinsicWidth(), - mEnterKey.iconPreview.getIntrinsicHeight()); - } - } - } - - void enableShiftLock() { - int index = getShiftKeyIndex(); - if (index >= 0) { - mShiftKey = getKeys().get(index); - if (mShiftKey instanceof LatinKey) { - ((LatinKey)mShiftKey).enableShiftLock(); - } - mOldShiftIcon = mShiftKey.icon; - mOldShiftPreviewIcon = mShiftKey.iconPreview; - } - } - - void setShiftLocked(boolean shiftLocked) { - if (mShiftKey != null) { - if (shiftLocked) { - mShiftKey.on = true; - mShiftKey.icon = mShiftLockIcon; - mShiftState = SHIFT_LOCKED; - } else { - mShiftKey.on = false; - mShiftKey.icon = mShiftLockIcon; - mShiftState = SHIFT_ON; - } - } - } - - boolean isShiftLocked() { - return mShiftState == SHIFT_LOCKED; - } - - @Override - public boolean setShifted(boolean shiftState) { - boolean shiftChanged = false; - if (mShiftKey != null) { - if (shiftState == false) { - shiftChanged = mShiftState != SHIFT_OFF; - mShiftState = SHIFT_OFF; - mShiftKey.on = false; - mShiftKey.icon = mOldShiftIcon; - } else { - if (mShiftState == SHIFT_OFF) { - shiftChanged = mShiftState == SHIFT_OFF; - mShiftState = SHIFT_ON; - mShiftKey.icon = mShiftLockIcon; - } - } - } else { - return super.setShifted(shiftState); - } - return shiftChanged; - } - - @Override - public boolean isShifted() { - if (mShiftKey != null) { - return mShiftState != SHIFT_OFF; - } else { - return super.isShifted(); - } - } - - public void setExtension(int resId) { - mExtensionResId = resId; - } - - public int getExtension() { - return mExtensionResId; - } - - private void setDefaultBounds(Drawable drawable) { - drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); - } - - public void setVoiceMode(boolean hasVoiceButton, boolean hasVoice) { - mHasVoiceButton = hasVoiceButton; - mVoiceEnabled = hasVoice; - updateF1Key(); - } - - private void updateF1Key() { - if (mF1Key == null) return; - if (m123Key != null && mIsAlphaKeyboard) { - if (mVoiceEnabled && !mHasVoiceButton) { - m123Key.icon = m123MicIcon; - m123Key.iconPreview = m123MicPreviewIcon; - m123Key.label = null; - } else { - m123Key.icon = null; - m123Key.iconPreview = null; - m123Key.label = m123Label; - } - } - - if (mHasVoiceButton && mVoiceEnabled) { - mF1Key.codes = new int[] { LatinKeyboardView.KEYCODE_VOICE }; - mF1Key.label = null; - mF1Key.icon = mMicIcon; - mF1Key.iconPreview = mMicPreviewIcon; - } else { - mF1Key.label = ","; - mF1Key.codes = new int[] { ',' }; - mF1Key.icon = null; - mF1Key.iconPreview = null; - } - } - - private void updateSpaceBarForLocale() { - if (mLocale != null) { - // Create the graphic for spacebar - Bitmap buffer = Bitmap.createBitmap(mSpaceKey.width, mSpaceIcon.getIntrinsicHeight(), - Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(buffer); - drawSpaceBar(canvas, buffer.getWidth(), buffer.getHeight(), 255); - mSpaceKey.icon = new BitmapDrawable(mRes, buffer); - mSpaceKey.repeatable = mLanguageSwitcher.getLocaleCount() < 2; - } else { - mSpaceKey.icon = mRes.getDrawable(R.drawable.sym_keyboard_space); - mSpaceKey.repeatable = true; - } - } - - private void drawSpaceBar(Canvas canvas, int width, int height, int opacity) { - canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); - Paint paint = new Paint(); - paint.setAntiAlias(true); - paint.setAlpha(opacity); - // Get the text size from the theme - paint.setTextSize(getTextSizeFromTheme(android.R.style.TextAppearance_Small, 14)); - paint.setTextAlign(Align.CENTER); - //// Draw a drop shadow for the text - //paint.setShadowLayer(2f, 0, 0, 0xFF000000); - final String language = getInputLanguage(mSpaceKey.width, paint); - final int ascent = (int) -paint.ascent(); - paint.setColor(0x80000000); - canvas.drawText(language, - width / 2, ascent - 1, paint); - paint.setColor(0xFF808080); - canvas.drawText(language, - width / 2, ascent, paint); - // Put arrows on either side of the text - if (mLanguageSwitcher.getLocaleCount() > 1) { - Rect bounds = new Rect(); - paint.getTextBounds(language, 0, language.length(), bounds); - drawButtonArrow(mButtonArrowLeftIcon, canvas, - (mSpaceKey.width - bounds.right) / 2 - - mButtonArrowLeftIcon.getIntrinsicWidth(), - (int) paint.getTextSize()); - drawButtonArrow(mButtonArrowRightIcon, canvas, - (mSpaceKey.width + bounds.right) / 2, (int) paint.getTextSize()); - } - // Draw the spacebar icon at the bottom - int x = (width - mSpaceIcon.getIntrinsicWidth()) / 2; - int y = height - mSpaceIcon.getIntrinsicHeight(); - mSpaceIcon.setBounds(x, y, - x + mSpaceIcon.getIntrinsicWidth(), y + mSpaceIcon.getIntrinsicHeight()); - mSpaceIcon.draw(canvas); - } - - private void drawButtonArrow(Drawable arrow, Canvas canvas, int x, int bottomY) { - arrow.setBounds(x, bottomY - arrow.getIntrinsicHeight(), x + arrow.getIntrinsicWidth(), - bottomY); - arrow.draw(canvas); - } - - private String getInputLanguage(int widthAvail, Paint paint) { - return chooseDisplayName(mLanguageSwitcher.getInputLocale(), widthAvail, paint); - } - - private String getNextInputLanguage(int widthAvail, Paint paint) { - return chooseDisplayName(mLanguageSwitcher.getNextInputLocale(), widthAvail, paint); - } - - private String getPrevInputLanguage(int widthAvail, Paint paint) { - return chooseDisplayName(mLanguageSwitcher.getPrevInputLocale(), widthAvail, paint); - } - - private String chooseDisplayName(Locale locale, int widthAvail, Paint paint) { - if (widthAvail < (int) (.35 * getMinWidth())) { - return LanguageSwitcher.toTitleCase(locale.getLanguage().substring(0, 2)); - } else { - return LanguageSwitcher.toTitleCase(locale.getDisplayLanguage(locale)); - } - } - - private void updateLocaleDrag(int diff) { - if (mSlidingLocaleIcon == null) { - mSlidingLocaleIcon = new SlidingLocaleDrawable(mSpacePreviewIcon, mSpaceKey.width, - mSpacePreviewIcon.getIntrinsicHeight()); - mSlidingLocaleIcon.setBounds(0, 0, mSpaceKey.width, - mSpacePreviewIcon.getIntrinsicHeight()); - mSpaceKey.iconPreview = mSlidingLocaleIcon; - } - mSlidingLocaleIcon.setDiff(diff); - if (Math.abs(diff) == Integer.MAX_VALUE) { - mSpaceKey.iconPreview = mSpacePreviewIcon; - } else { - mSpaceKey.iconPreview = mSlidingLocaleIcon; - } - mSpaceKey.iconPreview.invalidateSelf(); - } - - public int getLanguageChangeDirection() { - if (mSpaceKey == null || mLanguageSwitcher.getLocaleCount() < 2 - || Math.abs(mSpaceDragLastDiff) < mSpaceKey.width * SPACEBAR_DRAG_THRESHOLD ) { - return 0; // No change - } - return mSpaceDragLastDiff > 0 ? 1 : -1; - } - - public void setLanguageSwitcher(LanguageSwitcher switcher) { - mLanguageSwitcher = switcher; - Locale locale = mLanguageSwitcher.getLocaleCount() > 0 - ? mLanguageSwitcher.getInputLocale() - : null; - if (mLocale != null && mLocale.equals(locale)) return; - mLocale = locale; - updateSpaceBarForLocale(); - } - - boolean isCurrentlyInSpace() { - return mCurrentlyInSpace; - } - - void setPreferredLetters(int[] frequencies) { - mPrefLetterFrequencies = frequencies; - mPrefLetter = 0; - } - - void keyReleased() { - mCurrentlyInSpace = false; - mSpaceDragLastDiff = 0; - mPrefLetter = 0; - mPrefLetterX = 0; - mPrefLetterY = 0; - mPrefDistance = Integer.MAX_VALUE; - if (mSpaceKey != null) { - updateLocaleDrag(Integer.MAX_VALUE); - } - } - - /** - * Does the magic of locking the touch gesture into the spacebar when - * switching input languages. - */ - boolean isInside(LatinKey key, int x, int y) { - final int code = key.codes[0]; - if (code == KEYCODE_SHIFT || - code == KEYCODE_DELETE) { - y -= key.height / 10; - if (code == KEYCODE_SHIFT) x += key.width / 6; - if (code == KEYCODE_DELETE) x -= key.width / 6; - } else if (code == LatinIME.KEYCODE_SPACE) { - y += LatinKeyboard.sSpacebarVerticalCorrection; - if (mLanguageSwitcher.getLocaleCount() > 1) { - if (mCurrentlyInSpace) { - int diff = x - mSpaceDragStartX; - if (Math.abs(diff - mSpaceDragLastDiff) > 0) { - updateLocaleDrag(diff); - } - mSpaceDragLastDiff = diff; - return true; - } else { - boolean insideSpace = key.isInsideSuper(x, y); - if (insideSpace) { - mCurrentlyInSpace = true; - mSpaceDragStartX = x; - updateLocaleDrag(0); - } - return insideSpace; - } - } - } else if (mPrefLetterFrequencies != null) { - // New coordinate? Reset - if (mPrefLetterX != x || mPrefLetterY != y) { - mPrefLetter = 0; - mPrefDistance = Integer.MAX_VALUE; - } - // Handle preferred next letter - final int[] pref = mPrefLetterFrequencies; - if (mPrefLetter > 0) { - if (DEBUG_PREFERRED_LETTER && mPrefLetter == code - && !key.isInsideSuper(x, y)) { - Log.d(TAG, "CORRECTED !!!!!!"); - } - return mPrefLetter == code; - } else { - final boolean inside = key.isInsideSuper(x, y); - int[] nearby = getNearestKeys(x, y); - List<Key> nearbyKeys = getKeys(); - if (inside) { - // If it's a preferred letter - if (inPrefList(code, pref)) { - // Check if its frequency is much lower than a nearby key - mPrefLetter = code; - mPrefLetterX = x; - mPrefLetterY = y; - for (int i = 0; i < nearby.length; i++) { - Key k = nearbyKeys.get(nearby[i]); - if (k != key && inPrefList(k.codes[0], pref)) { - final int dist = distanceFrom(k, x, y); - if (dist < (int) (k.width * OVERLAP_PERCENTAGE_LOW_PROB) && - (pref[k.codes[0]] > pref[mPrefLetter] * 3)) { - mPrefLetter = k.codes[0]; - mPrefDistance = dist; - if (DEBUG_PREFERRED_LETTER) { - Log.d(TAG, "CORRECTED ALTHOUGH PREFERRED !!!!!!"); - } - break; - } - } - } - - return mPrefLetter == code; - } - } - - // Get the surrounding keys and intersect with the preferred list - // For all in the intersection - // if distance from touch point is within a reasonable distance - // make this the pref letter - // If no pref letter - // return inside; - // else return thiskey == prefletter; - - for (int i = 0; i < nearby.length; i++) { - Key k = nearbyKeys.get(nearby[i]); - if (inPrefList(k.codes[0], pref)) { - final int dist = distanceFrom(k, x, y); - if (dist < (int) (k.width * OVERLAP_PERCENTAGE_HIGH_PROB) - && dist < mPrefDistance) { - mPrefLetter = k.codes[0]; - mPrefLetterX = x; - mPrefLetterY = y; - mPrefDistance = dist; - } - } - } - // Didn't find any - if (mPrefLetter == 0) { - return inside; - } else { - return mPrefLetter == code; - } - } - } - - // Lock into the spacebar - if (mCurrentlyInSpace) return false; - - return key.isInsideSuper(x, y); - } - - private boolean inPrefList(int code, int[] pref) { - if (code < pref.length && code >= 0) return pref[code] > 0; - return false; - } - - private int distanceFrom(Key k, int x, int y) { - if (y > k.y && y < k.y + k.height) { - return Math.abs(k.x + k.width / 2 - x); - } else { - return Integer.MAX_VALUE; - } - } - - @Override - public int[] getNearestKeys(int x, int y) { - if (mCurrentlyInSpace) { - return new int[] { mSpaceKeyIndex }; - } else { - return super.getNearestKeys(x, y); - } - } - - private int indexOf(int code) { - List<Key> keys = getKeys(); - int count = keys.size(); - for (int i = 0; i < count; i++) { - if (keys.get(i).codes[0] == code) return i; - } - return -1; - } - - private int getTextSizeFromTheme(int style, int defValue) { - TypedArray array = mContext.getTheme().obtainStyledAttributes( - style, new int[] { android.R.attr.textSize }); - int textSize = array.getDimensionPixelSize(array.getResourceId(0, 0), defValue); - return textSize; - } - - class LatinKey extends Keyboard.Key { - - private boolean mShiftLockEnabled; - - public LatinKey(Resources res, Keyboard.Row parent, int x, int y, - XmlResourceParser parser) { - super(res, parent, x, y, parser); - if (popupCharacters != null && popupCharacters.length() == 0) { - // If there is a keyboard with no keys specified in popupCharacters - popupResId = 0; - } - } - - void enableShiftLock() { - mShiftLockEnabled = true; - } - - @Override - public void onReleased(boolean inside) { - if (!mShiftLockEnabled) { - super.onReleased(inside); - } else { - pressed = !pressed; - } - } - - /** - * Overriding this method so that we can reduce the target area for certain keys. - */ - @Override - public boolean isInside(int x, int y) { - boolean result = LatinKeyboard.this.isInside(this, x, y); - return result; - } - - boolean isInsideSuper(int x, int y) { - return super.isInside(x, y); - } - } - - /** - * Animation to be displayed on the spacebar preview popup when switching - * languages by swiping the spacebar. It draws the current, previous and - * next languages and moves them by the delta of touch movement on the spacebar. - */ - class SlidingLocaleDrawable extends Drawable { - - private int mWidth; - private int mHeight; - private Drawable mBackground; - private int mDiff; - private TextPaint mTextPaint; - private int mMiddleX; - private int mAscent; - private Drawable mLeftDrawable; - private Drawable mRightDrawable; - private boolean mHitThreshold; - private int mThreshold; - private String mCurrentLanguage; - private String mNextLanguage; - private String mPrevLanguage; - - public SlidingLocaleDrawable(Drawable background, int width, int height) { - mBackground = background; - mBackground.setBounds(0, 0, - mBackground.getIntrinsicWidth(), mBackground.getIntrinsicHeight()); - mWidth = width; - mHeight = height; - mTextPaint = new TextPaint(); - int textSize = getTextSizeFromTheme(android.R.style.TextAppearance_Medium, 18); - mTextPaint.setTextSize(textSize); - mTextPaint.setColor(0); - mTextPaint.setTextAlign(Align.CENTER); - mTextPaint.setAlpha(255); - mTextPaint.setAntiAlias(true); - mAscent = (int) mTextPaint.ascent(); - mMiddleX = (mWidth - mBackground.getIntrinsicWidth()) / 2; - mLeftDrawable = - mRes.getDrawable(R.drawable.sym_keyboard_feedback_language_arrows_left); - mRightDrawable = - mRes.getDrawable(R.drawable.sym_keyboard_feedback_language_arrows_right); - mLeftDrawable.setBounds(0, 0, - mLeftDrawable.getIntrinsicWidth(), mLeftDrawable.getIntrinsicHeight()); - mRightDrawable.setBounds(mWidth - mRightDrawable.getIntrinsicWidth(), 0, - mWidth, mRightDrawable.getIntrinsicHeight()); - mThreshold = ViewConfiguration.get(mContext).getScaledTouchSlop(); - } - - void setDiff(int diff) { - if (diff == Integer.MAX_VALUE) { - mHitThreshold = false; - mCurrentLanguage = null; - return; - } - mDiff = diff; - if (mDiff > mWidth) mDiff = mWidth; - if (mDiff < -mWidth) mDiff = -mWidth; - if (Math.abs(mDiff) > mThreshold) mHitThreshold = true; - invalidateSelf(); - } - - @Override - public void draw(Canvas canvas) { - canvas.save(); - if (mHitThreshold) { - mTextPaint.setColor(0xFF000000); - canvas.clipRect(0, 0, mWidth, mHeight); - if (mCurrentLanguage == null) { - mCurrentLanguage = getInputLanguage(mWidth, mTextPaint); - mNextLanguage = getNextInputLanguage(mWidth, mTextPaint); - mPrevLanguage = getPrevInputLanguage(mWidth, mTextPaint); - } - canvas.drawText(mCurrentLanguage, - mWidth / 2 + mDiff, -mAscent + 4, mTextPaint); - canvas.drawText(mNextLanguage, - mDiff - mWidth / 2, -mAscent + 4, mTextPaint); - canvas.drawText(mPrevLanguage, - mDiff + mWidth + mWidth / 2, -mAscent + 4, mTextPaint); - mLeftDrawable.draw(canvas); - mRightDrawable.draw(canvas); - } - if (mBackground != null) { - canvas.translate(mMiddleX, 0); - mBackground.draw(canvas); - } - canvas.restore(); - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - - @Override - public void setAlpha(int alpha) { - // Ignore - } - - @Override - public void setColorFilter(ColorFilter cf) { - // Ignore - } - - @Override - public int getIntrinsicWidth() { - return mWidth; - } - - @Override - public int getIntrinsicHeight() { - return mHeight; - } - } -} diff --git a/src/com/android/inputmethod/latin/LatinKeyboardView.java b/src/com/android/inputmethod/latin/LatinKeyboardView.java deleted file mode 100644 index 2686a93c6..000000000 --- a/src/com/android/inputmethod/latin/LatinKeyboardView.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import java.util.List; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.inputmethodservice.Keyboard; -import android.inputmethodservice.KeyboardView; -import android.inputmethodservice.Keyboard.Key; -import android.os.Handler; -import android.os.Message; -import android.os.SystemClock; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.widget.PopupWindow; - -public class LatinKeyboardView extends KeyboardView { - - static final int KEYCODE_OPTIONS = -100; - static final int KEYCODE_SHIFT_LONGPRESS = -101; - static final int KEYCODE_VOICE = -102; - static final int KEYCODE_F1 = -103; - static final int KEYCODE_NEXT_LANGUAGE = -104; - static final int KEYCODE_PREV_LANGUAGE = -105; - - private Keyboard mPhoneKeyboard; - - private boolean mExtensionVisible; - private LatinKeyboardView mExtension; - private PopupWindow mExtensionPopup; - private boolean mFirstEvent; - - public LatinKeyboardView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public LatinKeyboardView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - public void setPhoneKeyboard(Keyboard phoneKeyboard) { - mPhoneKeyboard = phoneKeyboard; - } - - @Override - protected boolean onLongPress(Key key) { - if (key.codes[0] == Keyboard.KEYCODE_MODE_CHANGE) { - getOnKeyboardActionListener().onKey(KEYCODE_OPTIONS, null); - return true; - } else if (key.codes[0] == Keyboard.KEYCODE_SHIFT) { - getOnKeyboardActionListener().onKey(KEYCODE_SHIFT_LONGPRESS, null); - invalidateAllKeys(); - return true; - } else if (key.codes[0] == '0' && getKeyboard() == mPhoneKeyboard) { - // Long pressing on 0 in phone number keypad gives you a '+'. - getOnKeyboardActionListener().onKey('+', null); - return true; - } else { - return super.onLongPress(key); - } - } - - @Override - public boolean onTouchEvent(MotionEvent me) { - LatinKeyboard keyboard = (LatinKeyboard) getKeyboard(); - if (DEBUG_LINE) { - mLastX = (int) me.getX(); - mLastY = (int) me.getY(); - invalidate(); - } - // Reset any bounding box controls in the keyboard - if (me.getAction() == MotionEvent.ACTION_DOWN) { - keyboard.keyReleased(); - } - - if (me.getAction() == MotionEvent.ACTION_UP) { - int languageDirection = keyboard.getLanguageChangeDirection(); - if (languageDirection != 0) { - getOnKeyboardActionListener().onKey( - languageDirection == 1 ? KEYCODE_NEXT_LANGUAGE : KEYCODE_PREV_LANGUAGE, - null); - me.setAction(MotionEvent.ACTION_CANCEL); - keyboard.keyReleased(); - return super.onTouchEvent(me); - } - } - - // If we don't have an extension keyboard, don't go any further. - if (keyboard.getExtension() == 0) { - return super.onTouchEvent(me); - } - if (me.getY() < 0) { - if (mExtensionVisible) { - int action = me.getAction(); - if (mFirstEvent) action = MotionEvent.ACTION_DOWN; - mFirstEvent = false; - MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), - action, - me.getX(), me.getY() + mExtension.getHeight(), me.getMetaState()); - boolean result = mExtension.onTouchEvent(translated); - translated.recycle(); - if (me.getAction() == MotionEvent.ACTION_UP - || me.getAction() == MotionEvent.ACTION_CANCEL) { - closeExtension(); - } - return result; - } else { - if (openExtension()) { - MotionEvent cancel = MotionEvent.obtain(me.getDownTime(), me.getEventTime(), - MotionEvent.ACTION_CANCEL, me.getX() - 100, me.getY() - 100, 0); - super.onTouchEvent(cancel); - cancel.recycle(); - if (mExtension.getHeight() > 0) { - MotionEvent translated = MotionEvent.obtain(me.getEventTime(), - me.getEventTime(), - MotionEvent.ACTION_DOWN, - me.getX(), me.getY() + mExtension.getHeight(), - me.getMetaState()); - mExtension.onTouchEvent(translated); - translated.recycle(); - } else { - mFirstEvent = true; - } - } - return true; - } - } else if (mExtensionVisible) { - closeExtension(); - // Send a down event into the main keyboard first - MotionEvent down = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), - MotionEvent.ACTION_DOWN, - me.getX(), me.getY(), me.getMetaState()); - super.onTouchEvent(down); - down.recycle(); - // Send the actual event - return super.onTouchEvent(me); - } else { - return super.onTouchEvent(me); - } - } - - private boolean openExtension() { - if (((LatinKeyboard) getKeyboard()).getExtension() == 0) return false; - makePopupWindow(); - mExtensionVisible = true; - return true; - } - - private void makePopupWindow() { - if (mExtensionPopup == null) { - int[] windowLocation = new int[2]; - mExtensionPopup = new PopupWindow(getContext()); - mExtensionPopup.setBackgroundDrawable(null); - LayoutInflater li = (LayoutInflater) getContext().getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - mExtension = (LatinKeyboardView) li.inflate(R.layout.input_trans, null); - mExtension.setOnKeyboardActionListener((LatinIME) getContext()); - mExtension.setPopupParent(this); - mExtension.setPopupOffset(0, -windowLocation[1]); - Keyboard keyboard; - mExtension.setKeyboard(keyboard = new LatinKeyboard(getContext(), - ((LatinKeyboard) getKeyboard()).getExtension())); - mExtensionPopup.setContentView(mExtension); - mExtensionPopup.setWidth(getWidth()); - mExtensionPopup.setHeight(keyboard.getHeight()); - getLocationInWindow(windowLocation); - // TODO: Fix the "- 30". - mExtension.setPopupOffset(0, -windowLocation[1] - 30); - mExtensionPopup.showAtLocation(this, 0, 0, -keyboard.getHeight() - + windowLocation[1]); - } else { - mExtension.setVisibility(VISIBLE); - } - } - - @Override - public void closing() { - super.closing(); - if (mExtensionPopup != null && mExtensionPopup.isShowing()) { - mExtensionPopup.dismiss(); - mExtensionPopup = null; - } - } - - private void closeExtension() { - mExtension.setVisibility(INVISIBLE); - mExtension.closing(); - mExtensionVisible = false; - } - - /**************************** INSTRUMENTATION *******************************/ - - static final boolean DEBUG_AUTO_PLAY = false; - static final boolean DEBUG_LINE = false; - private static final int MSG_TOUCH_DOWN = 1; - private static final int MSG_TOUCH_UP = 2; - - Handler mHandler2; - - private String mStringToPlay; - private int mStringIndex; - private boolean mDownDelivered; - private Key[] mAsciiKeys = new Key[256]; - private boolean mPlaying; - private int mLastX; - private int mLastY; - private Paint mPaint; - - @Override - public void setKeyboard(Keyboard k) { - super.setKeyboard(k); - if (DEBUG_AUTO_PLAY) { - findKeys(); - if (mHandler2 == null) { - mHandler2 = new Handler() { - @Override - public void handleMessage(Message msg) { - removeMessages(MSG_TOUCH_DOWN); - removeMessages(MSG_TOUCH_UP); - if (mPlaying == false) return; - - switch (msg.what) { - case MSG_TOUCH_DOWN: - if (mStringIndex >= mStringToPlay.length()) { - mPlaying = false; - return; - } - char c = mStringToPlay.charAt(mStringIndex); - while (c > 255 || mAsciiKeys[(int) c] == null) { - mStringIndex++; - if (mStringIndex >= mStringToPlay.length()) { - mPlaying = false; - return; - } - c = mStringToPlay.charAt(mStringIndex); - } - int x = mAsciiKeys[c].x + 10; - int y = mAsciiKeys[c].y + 26; - MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(), - SystemClock.uptimeMillis(), - MotionEvent.ACTION_DOWN, x, y, 0); - LatinKeyboardView.this.dispatchTouchEvent(me); - me.recycle(); - sendEmptyMessageDelayed(MSG_TOUCH_UP, 500); // Deliver up in 500ms if nothing else - // happens - mDownDelivered = true; - break; - case MSG_TOUCH_UP: - char cUp = mStringToPlay.charAt(mStringIndex); - int x2 = mAsciiKeys[cUp].x + 10; - int y2 = mAsciiKeys[cUp].y + 26; - mStringIndex++; - - MotionEvent me2 = MotionEvent.obtain(SystemClock.uptimeMillis(), - SystemClock.uptimeMillis(), - MotionEvent.ACTION_UP, x2, y2, 0); - LatinKeyboardView.this.dispatchTouchEvent(me2); - me2.recycle(); - sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 500); // Deliver up in 500ms if nothing else - // happens - mDownDelivered = false; - break; - } - } - }; - - } - } - } - - private void findKeys() { - List<Key> keys = getKeyboard().getKeys(); - // Get the keys on this keyboard - for (int i = 0; i < keys.size(); i++) { - int code = keys.get(i).codes[0]; - if (code >= 0 && code <= 255) { - mAsciiKeys[code] = keys.get(i); - } - } - } - - void startPlaying(String s) { - if (!DEBUG_AUTO_PLAY) return; - if (s == null) return; - mStringToPlay = s.toLowerCase(); - mPlaying = true; - mDownDelivered = false; - mStringIndex = 0; - mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 10); - } - - @Override - public void draw(Canvas c) { - super.draw(c); - if (DEBUG_AUTO_PLAY && mPlaying) { - mHandler2.removeMessages(MSG_TOUCH_DOWN); - mHandler2.removeMessages(MSG_TOUCH_UP); - if (mDownDelivered) { - mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_UP, 20); - } else { - mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 20); - } - } - if (DEBUG_LINE) { - if (mPaint == null) { - mPaint = new Paint(); - mPaint.setColor(0x80FFFFFF); - mPaint.setAntiAlias(false); - } - c.drawLine(mLastX, 0, mLastX, getHeight(), mPaint); - c.drawLine(0, mLastY, getWidth(), mLastY, mPaint); - } - } -} diff --git a/src/com/android/inputmethod/latin/Suggest.java b/src/com/android/inputmethod/latin/Suggest.java deleted file mode 100755 index 712b9cf37..000000000 --- a/src/com/android/inputmethod/latin/Suggest.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import android.content.Context; -import android.text.AutoText; -import android.text.TextUtils; -import android.util.Log; -import android.view.View; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import com.android.inputmethod.latin.WordComposer; - -/** - * This class loads a dictionary and provides a list of suggestions for a given sequence of - * characters. This includes corrections and completions. - * @hide pending API Council Approval - */ -public class Suggest implements Dictionary.WordCallback { - - public static final int CORRECTION_NONE = 0; - public static final int CORRECTION_BASIC = 1; - public static final int CORRECTION_FULL = 2; - - private static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000; - - private BinaryDictionary mMainDict; - - private Dictionary mUserDictionary; - - private Dictionary mAutoDictionary; - - private Dictionary mContactsDictionary; - - private int mPrefMaxSuggestions = 12; - - private boolean mAutoTextEnabled; - - private int[] mPriorities = new int[mPrefMaxSuggestions]; - // Handle predictive correction for only the first 1280 characters for performance reasons - // If we support scripts that need latin characters beyond that, we should probably use some - // kind of a sparse array or language specific list with a mapping lookup table. - // 1280 is the size of the BASE_CHARS array in ExpandableDictionary, which is a basic set of - // latin characters. - private int[] mNextLettersFrequencies = new int[1280]; - private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>(); - private ArrayList<CharSequence> mStringPool = new ArrayList<CharSequence>(); - private boolean mHaveCorrection; - private CharSequence mOriginalWord; - private String mLowerOriginalWord; - private boolean mCapitalize; - - private int mCorrectionMode = CORRECTION_BASIC; - - - public Suggest(Context context, int dictionaryResId) { - mMainDict = new BinaryDictionary(context, dictionaryResId); - for (int i = 0; i < mPrefMaxSuggestions; i++) { - StringBuilder sb = new StringBuilder(32); - mStringPool.add(sb); - } - } - - public void setAutoTextEnabled(boolean enabled) { - mAutoTextEnabled = enabled; - } - - public int getCorrectionMode() { - return mCorrectionMode; - } - - public void setCorrectionMode(int mode) { - mCorrectionMode = mode; - } - - public boolean hasMainDictionary() { - return mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD; - } - - /** - * Sets an optional user dictionary resource to be loaded. The user dictionary is consulted - * before the main dictionary, if set. - */ - public void setUserDictionary(Dictionary userDictionary) { - mUserDictionary = userDictionary; - } - - /** - * Sets an optional contacts dictionary resource to be loaded. - */ - public void setContactsDictionary(Dictionary userDictionary) { - mContactsDictionary = userDictionary; - } - - public void setAutoDictionary(Dictionary autoDictionary) { - mAutoDictionary = autoDictionary; - } - - /** - * Number of suggestions to generate from the input key sequence. This has - * to be a number between 1 and 100 (inclusive). - * @param maxSuggestions - * @throws IllegalArgumentException if the number is out of range - */ - public void setMaxSuggestions(int maxSuggestions) { - if (maxSuggestions < 1 || maxSuggestions > 100) { - throw new IllegalArgumentException("maxSuggestions must be between 1 and 100"); - } - mPrefMaxSuggestions = maxSuggestions; - mPriorities = new int[mPrefMaxSuggestions]; - collectGarbage(); - while (mStringPool.size() < mPrefMaxSuggestions) { - StringBuilder sb = new StringBuilder(32); - mStringPool.add(sb); - } - } - - private boolean haveSufficientCommonality(String original, CharSequence suggestion) { - final int originalLength = original.length(); - final int suggestionLength = suggestion.length(); - final int minLength = Math.min(originalLength, suggestionLength); - if (minLength <= 2) return true; - int matching = 0; - int lessMatching = 0; // Count matches if we skip one character - int i; - for (i = 0; i < minLength; i++) { - final char origChar = ExpandableDictionary.toLowerCase(original.charAt(i)); - if (origChar == ExpandableDictionary.toLowerCase(suggestion.charAt(i))) { - matching++; - lessMatching++; - } else if (i + 1 < suggestionLength - && origChar == ExpandableDictionary.toLowerCase(suggestion.charAt(i + 1))) { - lessMatching++; - } - } - matching = Math.max(matching, lessMatching); - - if (minLength <= 4) { - return matching >= 2; - } else { - return matching > minLength / 2; - } - } - - /** - * Returns a list of words that match the list of character codes passed in. - * This list will be overwritten the next time this function is called. - * @param a view for retrieving the context for AutoText - * @param codes the list of codes. Each list item contains an array of character codes - * in order of probability where the character at index 0 in the array has the highest - * probability. - * @return list of suggestions. - */ - public List<CharSequence> getSuggestions(View view, WordComposer wordComposer, - boolean includeTypedWordIfValid) { - mHaveCorrection = false; - mCapitalize = wordComposer.isCapitalized(); - collectGarbage(); - Arrays.fill(mPriorities, 0); - Arrays.fill(mNextLettersFrequencies, 0); - - // Save a lowercase version of the original word - mOriginalWord = wordComposer.getTypedWord(); - if (mOriginalWord != null) { - mOriginalWord = mOriginalWord.toString(); - mLowerOriginalWord = mOriginalWord.toString().toLowerCase(); - } else { - mLowerOriginalWord = ""; - } - // Search the dictionary only if there are at least 2 characters - if (wordComposer.size() > 1) { - if (mUserDictionary != null || mContactsDictionary != null) { - if (mUserDictionary != null) { - mUserDictionary.getWords(wordComposer, this, mNextLettersFrequencies); - } - if (mContactsDictionary != null) { - mContactsDictionary.getWords(wordComposer, this, mNextLettersFrequencies); - } - - if (mSuggestions.size() > 0 && isValidWord(mOriginalWord) - && mCorrectionMode == CORRECTION_FULL) { - mHaveCorrection = true; - } - } - mMainDict.getWords(wordComposer, this, mNextLettersFrequencies); - if (mCorrectionMode == CORRECTION_FULL && mSuggestions.size() > 0) { - mHaveCorrection = true; - } - } - if (mOriginalWord != null) { - mSuggestions.add(0, mOriginalWord.toString()); - } - - // Check if the first suggestion has a minimum number of characters in common - if (mCorrectionMode == CORRECTION_FULL && mSuggestions.size() > 1) { - if (!haveSufficientCommonality(mLowerOriginalWord, mSuggestions.get(1))) { - mHaveCorrection = false; - } - } - - if (mAutoTextEnabled) { - int i = 0; - int max = 6; - // Don't autotext the suggestions from the dictionaries - if (mCorrectionMode == CORRECTION_BASIC) max = 1; - while (i < mSuggestions.size() && i < max) { - String suggestedWord = mSuggestions.get(i).toString().toLowerCase(); - CharSequence autoText = - AutoText.get(suggestedWord, 0, suggestedWord.length(), view); - // Is there an AutoText correction? - boolean canAdd = autoText != null; - // Is that correction already the current prediction (or original word)? - canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i)); - // Is that correction already the next predicted word? - if (canAdd && i + 1 < mSuggestions.size() && mCorrectionMode != CORRECTION_BASIC) { - canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i + 1)); - } - if (canAdd) { - mHaveCorrection = true; - mSuggestions.add(i + 1, autoText); - i++; - } - i++; - } - } - - removeDupes(); - return mSuggestions; - } - - public int[] getNextLettersFrequencies() { - return mNextLettersFrequencies; - } - - private void removeDupes() { - final ArrayList<CharSequence> suggestions = mSuggestions; - if (suggestions.size() < 2) return; - int i = 1; - // Don't cache suggestions.size(), since we may be removing items - while (i < suggestions.size()) { - final CharSequence cur = suggestions.get(i); - // Compare each candidate with each previous candidate - for (int j = 0; j < i; j++) { - CharSequence previous = suggestions.get(j); - if (TextUtils.equals(cur, previous)) { - removeFromSuggestions(i); - i--; - break; - } - } - i++; - } - } - - private void removeFromSuggestions(int index) { - CharSequence garbage = mSuggestions.remove(index); - if (garbage != null && garbage instanceof StringBuilder) { - mStringPool.add(garbage); - } - } - - public boolean hasMinimalCorrection() { - return mHaveCorrection; - } - - private boolean compareCaseInsensitive(final String mLowerOriginalWord, - final char[] word, final int offset, final int length) { - final int originalLength = mLowerOriginalWord.length(); - if (originalLength == length && Character.isUpperCase(word[offset])) { - for (int i = 0; i < originalLength; i++) { - if (mLowerOriginalWord.charAt(i) != Character.toLowerCase(word[offset+i])) { - return false; - } - } - return true; - } - return false; - } - - public boolean addWord(final char[] word, final int offset, final int length, final int freq) { - int pos = 0; - final int[] priorities = mPriorities; - final int prefMaxSuggestions = mPrefMaxSuggestions; - // Check if it's the same word, only caps are different - if (compareCaseInsensitive(mLowerOriginalWord, word, offset, length)) { - pos = 0; - } else { - // Check the last one's priority and bail - if (priorities[prefMaxSuggestions - 1] >= freq) return true; - while (pos < prefMaxSuggestions) { - if (priorities[pos] < freq - || (priorities[pos] == freq && length < mSuggestions - .get(pos).length())) { - break; - } - pos++; - } - } - - if (pos >= prefMaxSuggestions) { - return true; - } - System.arraycopy(priorities, pos, priorities, pos + 1, - prefMaxSuggestions - pos - 1); - priorities[pos] = freq; - int poolSize = mStringPool.size(); - StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1) - : new StringBuilder(32); - sb.setLength(0); - if (mCapitalize) { - sb.append(Character.toUpperCase(word[offset])); - if (length > 1) { - sb.append(word, offset + 1, length - 1); - } - } else { - sb.append(word, offset, length); - } - mSuggestions.add(pos, sb); - if (mSuggestions.size() > prefMaxSuggestions) { - CharSequence garbage = mSuggestions.remove(prefMaxSuggestions); - if (garbage instanceof StringBuilder) { - mStringPool.add(garbage); - } - } - return true; - } - - public boolean isValidWord(final CharSequence word) { - if (word == null || word.length() == 0) { - return false; - } - return (mCorrectionMode == CORRECTION_FULL && mMainDict.isValidWord(word)) - || (mCorrectionMode > CORRECTION_NONE && - ((mUserDictionary != null && mUserDictionary.isValidWord(word))) - || (mAutoDictionary != null && mAutoDictionary.isValidWord(word)) - || (mContactsDictionary != null && mContactsDictionary.isValidWord(word))); - } - - private void collectGarbage() { - int poolSize = mStringPool.size(); - int garbageSize = mSuggestions.size(); - while (poolSize < mPrefMaxSuggestions && garbageSize > 0) { - CharSequence garbage = mSuggestions.get(garbageSize - 1); - if (garbage != null && garbage instanceof StringBuilder) { - mStringPool.add(garbage); - poolSize++; - } - garbageSize--; - } - if (poolSize == mPrefMaxSuggestions + 1) { - Log.w("Suggest", "String pool got too big: " + poolSize); - } - mSuggestions.clear(); - } - - public void close() { - if (mMainDict != null) { - mMainDict.close(); - } - } -} diff --git a/src/com/android/inputmethod/latin/TextEntryState.java b/src/com/android/inputmethod/latin/TextEntryState.java deleted file mode 100644 index c5e8ad9a1..000000000 --- a/src/com/android/inputmethod/latin/TextEntryState.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import android.content.Context; -import android.text.format.DateFormat; -import android.util.Log; - -import android.inputmethodservice.Keyboard.Key; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Calendar; - -public class TextEntryState { - - private static boolean LOGGING = false; - - private static int sBackspaceCount = 0; - - private static int sAutoSuggestCount = 0; - - private static int sAutoSuggestUndoneCount = 0; - - private static int sManualSuggestCount = 0; - - private static int sWordNotInDictionaryCount = 0; - - private static int sSessionCount = 0; - - private static int sTypedChars; - - private static int sActualChars; - - private static final String[] STATES = { - "Unknown", - "Start", - "In word", - "Accepted default", - "Picked suggestion", - "Punc. after word", - "Punc. after accepted", - "Space after accepted", - "Space after picked", - "Undo commit" - }; - - public static final int STATE_UNKNOWN = 0; - public static final int STATE_START = 1; - public static final int STATE_IN_WORD = 2; - public static final int STATE_ACCEPTED_DEFAULT = 3; - public static final int STATE_PICKED_SUGGESTION = 4; - public static final int STATE_PUNCTUATION_AFTER_WORD = 5; - public static final int STATE_PUNCTUATION_AFTER_ACCEPTED = 6; - public static final int STATE_SPACE_AFTER_ACCEPTED = 7; - public static final int STATE_SPACE_AFTER_PICKED = 8; - public static final int STATE_UNDO_COMMIT = 9; - - private static int sState = STATE_UNKNOWN; - - private static FileOutputStream sKeyLocationFile; - private static FileOutputStream sUserActionFile; - - public static void newSession(Context context) { - sSessionCount++; - sAutoSuggestCount = 0; - sBackspaceCount = 0; - sAutoSuggestUndoneCount = 0; - sManualSuggestCount = 0; - sWordNotInDictionaryCount = 0; - sTypedChars = 0; - sActualChars = 0; - sState = STATE_START; - - if (LOGGING) { - try { - sKeyLocationFile = context.openFileOutput("key.txt", Context.MODE_APPEND); - sUserActionFile = context.openFileOutput("action.txt", Context.MODE_APPEND); - } catch (IOException ioe) { - Log.e("TextEntryState", "Couldn't open file for output: " + ioe); - } - } - } - - public static void endSession() { - if (sKeyLocationFile == null) { - return; - } - try { - sKeyLocationFile.close(); - // Write to log file - // Write timestamp, settings, - String out = DateFormat.format("MM:dd hh:mm:ss", Calendar.getInstance().getTime()) - .toString() - + " BS: " + sBackspaceCount - + " auto: " + sAutoSuggestCount - + " manual: " + sManualSuggestCount - + " typed: " + sWordNotInDictionaryCount - + " undone: " + sAutoSuggestUndoneCount - + " saved: " + ((float) (sActualChars - sTypedChars) / sActualChars) - + "\n"; - sUserActionFile.write(out.getBytes()); - sUserActionFile.close(); - sKeyLocationFile = null; - sUserActionFile = null; - } catch (IOException ioe) { - - } - } - - public static void acceptedDefault(CharSequence typedWord, CharSequence actualWord) { - if (typedWord == null) return; - if (!typedWord.equals(actualWord)) { - sAutoSuggestCount++; - } - sTypedChars += typedWord.length(); - sActualChars += actualWord.length(); - sState = STATE_ACCEPTED_DEFAULT; - } - - public static void acceptedTyped(CharSequence typedWord) { - sWordNotInDictionaryCount++; - sState = STATE_PICKED_SUGGESTION; - } - - public static void acceptedSuggestion(CharSequence typedWord, CharSequence actualWord) { - sManualSuggestCount++; - if (typedWord.equals(actualWord)) { - acceptedTyped(typedWord); - } - sState = STATE_PICKED_SUGGESTION; - } - - public static void typedCharacter(char c, boolean isSeparator) { - boolean isSpace = c == ' '; - switch (sState) { - case STATE_IN_WORD: - if (isSpace || isSeparator) { - sState = STATE_START; - } else { - // State hasn't changed. - } - break; - case STATE_ACCEPTED_DEFAULT: - case STATE_SPACE_AFTER_PICKED: - if (isSpace) { - sState = STATE_SPACE_AFTER_ACCEPTED; - } else if (isSeparator) { - sState = STATE_PUNCTUATION_AFTER_ACCEPTED; - } else { - sState = STATE_IN_WORD; - } - break; - case STATE_PICKED_SUGGESTION: - if (isSpace) { - sState = STATE_SPACE_AFTER_PICKED; - } else if (isSeparator) { - // Swap - sState = STATE_PUNCTUATION_AFTER_ACCEPTED; - } else { - sState = STATE_IN_WORD; - } - break; - case STATE_START: - case STATE_UNKNOWN: - case STATE_SPACE_AFTER_ACCEPTED: - case STATE_PUNCTUATION_AFTER_ACCEPTED: - case STATE_PUNCTUATION_AFTER_WORD: - if (!isSpace && !isSeparator) { - sState = STATE_IN_WORD; - } else { - sState = STATE_START; - } - break; - case STATE_UNDO_COMMIT: - if (isSpace || isSeparator) { - sState = STATE_ACCEPTED_DEFAULT; - } else { - sState = STATE_IN_WORD; - } - } - } - - public static void backspace() { - if (sState == STATE_ACCEPTED_DEFAULT) { - sState = STATE_UNDO_COMMIT; - sAutoSuggestUndoneCount++; - } else if (sState == STATE_UNDO_COMMIT) { - sState = STATE_IN_WORD; - } - sBackspaceCount++; - } - - public static void reset() { - sState = STATE_START; - } - - public static int getState() { - return sState; - } - - public static void keyPressedAt(Key key, int x, int y) { - if (LOGGING && sKeyLocationFile != null && key.codes[0] >= 32) { - String out = - "KEY: " + (char) key.codes[0] - + " X: " + x - + " Y: " + y - + " MX: " + (key.x + key.width / 2) - + " MY: " + (key.y + key.height / 2) - + "\n"; - try { - sKeyLocationFile.write(out.getBytes()); - } catch (IOException ioe) { - // TODO: May run out of space - } - } - } -} - diff --git a/src/com/android/inputmethod/latin/Tutorial.java b/src/com/android/inputmethod/latin/Tutorial.java deleted file mode 100644 index 03d4858c4..000000000 --- a/src/com/android/inputmethod/latin/Tutorial.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import android.content.Context; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.Message; -import android.text.Layout; -import android.text.SpannableStringBuilder; -import android.text.StaticLayout; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; -import android.widget.PopupWindow; -import android.widget.TextView; - -import java.util.ArrayList; -import java.util.List; - -public class Tutorial implements OnTouchListener { - - private List<Bubble> mBubbles = new ArrayList<Bubble>(); - private long mStartTime; - private static final long MINIMUM_TIME = 6000; - private static final long MAXIMUM_TIME = 20000; - private View mInputView; - private LatinIME mIme; - private int[] mLocation = new int[2]; - private int mBubblePointerOffset; - - private static final int MSG_SHOW_BUBBLE = 0; - - private int mBubbleIndex; - - Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_SHOW_BUBBLE: - Bubble bubba = (Bubble) msg.obj; - bubba.show(mLocation[0], mLocation[1]); - break; - } - } - }; - - class Bubble { - Drawable bubbleBackground; - int x; - int y; - int width; - int gravity; - CharSequence text; - boolean dismissOnTouch; - boolean dismissOnClose; - PopupWindow window; - TextView textView; - View inputView; - - Bubble(Context context, View inputView, - int backgroundResource, int bx, int by, int textResource1, int textResource2) { - bubbleBackground = context.getResources().getDrawable(backgroundResource); - x = bx; - y = by; - width = (int) (inputView.getWidth() * 0.9); - this.gravity = Gravity.TOP | Gravity.LEFT; - text = new SpannableStringBuilder() - .append(context.getResources().getText(textResource1)) - .append("\n") - .append(context.getResources().getText(textResource2)); - this.dismissOnTouch = true; - this.dismissOnClose = false; - this.inputView = inputView; - window = new PopupWindow(context); - window.setBackgroundDrawable(null); - LayoutInflater inflate = - (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - textView = (TextView) inflate.inflate(R.layout.bubble_text, null); - textView.setBackgroundDrawable(bubbleBackground); - textView.setText(text); - //textView.setText(textResource1); - window.setContentView(textView); - window.setFocusable(false); - window.setTouchable(true); - window.setOutsideTouchable(false); - } - - private int chooseSize(PopupWindow pop, View parentView, CharSequence text, TextView tv) { - int wid = tv.getPaddingLeft() + tv.getPaddingRight(); - int ht = tv.getPaddingTop() + tv.getPaddingBottom(); - - /* - * Figure out how big the text would be if we laid it out to the - * full width of this view minus the border. - */ - int cap = width - wid; - - Layout l = new StaticLayout(text, tv.getPaint(), cap, - Layout.Alignment.ALIGN_NORMAL, 1, 0, true); - float max = 0; - for (int i = 0; i < l.getLineCount(); i++) { - max = Math.max(max, l.getLineWidth(i)); - } - - /* - * Now set the popup size to be big enough for the text plus the border. - */ - pop.setWidth(width); - pop.setHeight(ht + l.getHeight()); - return l.getHeight(); - } - - void show(int offx, int offy) { - int textHeight = chooseSize(window, inputView, text, textView); - offy -= textView.getPaddingTop() + textHeight; - if (inputView.getVisibility() == View.VISIBLE - && inputView.getWindowVisibility() == View.VISIBLE) { - try { - if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) offy -= window.getHeight(); - if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) offx -= window.getWidth(); - textView.setOnTouchListener(new View.OnTouchListener() { - public boolean onTouch(View view, MotionEvent me) { - Tutorial.this.next(); - return true; - } - }); - window.showAtLocation(inputView, Gravity.NO_GRAVITY, x + offx, y + offy); - } catch (Exception e) { - // Input view is not valid - } - } - } - - void hide() { - if (window.isShowing()) { - textView.setOnTouchListener(null); - window.dismiss(); - } - } - - boolean isShowing() { - return window.isShowing(); - } - } - - public Tutorial(LatinIME ime, LatinKeyboardView inputView) { - Context context = inputView.getContext(); - mIme = ime; - int inputWidth = inputView.getWidth(); - final int x = inputWidth / 20; // Half of 1/10th - mBubblePointerOffset = inputView.getContext().getResources() - .getDimensionPixelOffset(R.dimen.bubble_pointer_offset); - Bubble bWelcome = new Bubble(context, inputView, - R.drawable.dialog_bubble_step02, x, 0, - R.string.tip_to_open_keyboard, R.string.touch_to_continue); - mBubbles.add(bWelcome); - Bubble bAccents = new Bubble(context, inputView, - R.drawable.dialog_bubble_step02, x, 0, - R.string.tip_to_view_accents, R.string.touch_to_continue); - mBubbles.add(bAccents); - Bubble b123 = new Bubble(context, inputView, - R.drawable.dialog_bubble_step07, x, 0, - R.string.tip_to_open_symbols, R.string.touch_to_continue); - mBubbles.add(b123); - Bubble bABC = new Bubble(context, inputView, - R.drawable.dialog_bubble_step07, x, 0, - R.string.tip_to_close_symbols, R.string.touch_to_continue); - mBubbles.add(bABC); - Bubble bSettings = new Bubble(context, inputView, - R.drawable.dialog_bubble_step07, x, 0, - R.string.tip_to_launch_settings, R.string.touch_to_continue); - mBubbles.add(bSettings); - Bubble bDone = new Bubble(context, inputView, - R.drawable.dialog_bubble_step02, x, 0, - R.string.tip_to_start_typing, R.string.touch_to_finish); - mBubbles.add(bDone); - mInputView = inputView; - } - - void start() { - mInputView.getLocationInWindow(mLocation); - mBubbleIndex = -1; - mInputView.setOnTouchListener(this); - next(); - } - - boolean next() { - if (mBubbleIndex >= 0) { - // If the bubble is not yet showing, don't move to the next. - if (!mBubbles.get(mBubbleIndex).isShowing()) { - return true; - } - // Hide all previous bubbles as well, as they may have had a delayed show - for (int i = 0; i <= mBubbleIndex; i++) { - mBubbles.get(i).hide(); - } - } - mBubbleIndex++; - if (mBubbleIndex >= mBubbles.size()) { - mInputView.setOnTouchListener(null); - mIme.sendDownUpKeyEvents(-1); // Inform the setupwizard that tutorial is in last bubble - mIme.tutorialDone(); - return false; - } - if (mBubbleIndex == 3 || mBubbleIndex == 4) { - mIme.mKeyboardSwitcher.toggleSymbols(); - } - mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_SHOW_BUBBLE, mBubbles.get(mBubbleIndex)), 500); - return true; - } - - void hide() { - for (int i = 0; i < mBubbles.size(); i++) { - mBubbles.get(i).hide(); - } - mInputView.setOnTouchListener(null); - } - - boolean close() { - mHandler.removeMessages(MSG_SHOW_BUBBLE); - hide(); - return true; - } - - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - next(); - } - return true; - } -} diff --git a/src/com/android/inputmethod/latin/UserDictionary.java b/src/com/android/inputmethod/latin/UserDictionary.java deleted file mode 100644 index 4b98eacce..000000000 --- a/src/com/android/inputmethod/latin/UserDictionary.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.database.ContentObserver; -import android.database.Cursor; -import android.net.Uri; -import android.provider.UserDictionary.Words; - -public class UserDictionary extends ExpandableDictionary { - - private static final String[] PROJECTION = { - Words._ID, - Words.WORD, - Words.FREQUENCY - }; - - private static final int INDEX_WORD = 1; - private static final int INDEX_FREQUENCY = 2; - - private ContentObserver mObserver; - - private boolean mRequiresReload; - private String mLocale; - - public UserDictionary(Context context, String locale) { - super(context); - mLocale = locale; - // Perform a managed query. The Activity will handle closing and requerying the cursor - // when needed. - ContentResolver cres = context.getContentResolver(); - - cres.registerContentObserver(Words.CONTENT_URI, true, mObserver = new ContentObserver(null) { - @Override - public void onChange(boolean self) { - mRequiresReload = true; - } - }); - - loadDictionary(); - } - - public synchronized void close() { - if (mObserver != null) { - getContext().getContentResolver().unregisterContentObserver(mObserver); - mObserver = null; - } - } - - private synchronized void loadDictionary() { - Cursor cursor = getContext().getContentResolver() - .query(Words.CONTENT_URI, PROJECTION, "(locale IS NULL) or (locale=?)", - new String[] { mLocale }, null); - addWords(cursor); - mRequiresReload = false; - } - - /** - * Adds a word to the dictionary and makes it persistent. - * @param word the word to add. If the word is capitalized, then the dictionary will - * recognize it as a capitalized word when searched. - * @param frequency the frequency of occurrence of the word. A frequency of 255 is considered - * the highest. - * @TODO use a higher or float range for frequency - */ - @Override - public synchronized void addWord(String word, int frequency) { - if (mRequiresReload) loadDictionary(); - // Safeguard against adding long words. Can cause stack overflow. - if (word.length() >= getMaxWordLength()) return; - - super.addWord(word, frequency); - - // Update the user dictionary provider - ContentValues values = new ContentValues(5); - values.put(Words.WORD, word); - values.put(Words.FREQUENCY, frequency); - values.put(Words.LOCALE, mLocale); - values.put(Words.APP_ID, 0); - - getContext().getContentResolver().insert(Words.CONTENT_URI, values); - // In case the above does a synchronous callback of the change observer - mRequiresReload = false; - } - - @Override - public synchronized void getWords(final WordComposer codes, final WordCallback callback, - int[] nextLettersFrequencies) { - if (mRequiresReload) loadDictionary(); - super.getWords(codes, callback, nextLettersFrequencies); - } - - @Override - public synchronized boolean isValidWord(CharSequence word) { - if (mRequiresReload) loadDictionary(); - return super.isValidWord(word); - } - - private void addWords(Cursor cursor) { - clearDictionary(); - - final int maxWordLength = getMaxWordLength(); - if (cursor.moveToFirst()) { - while (!cursor.isAfterLast()) { - String word = cursor.getString(INDEX_WORD); - int frequency = cursor.getInt(INDEX_FREQUENCY); - // Safeguard against adding really long words. Stack may overflow due - // to recursion - if (word.length() < maxWordLength) { - super.addWord(word, frequency); - } - cursor.moveToNext(); - } - } - cursor.close(); - } -} diff --git a/src/com/android/inputmethod/latin/WordComposer.java b/src/com/android/inputmethod/latin/WordComposer.java deleted file mode 100644 index e97cb24ba..000000000 --- a/src/com/android/inputmethod/latin/WordComposer.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import java.util.ArrayList; -import java.util.List; - -/** - * A place to store the currently composing word with information such as adjacent key codes as well - */ -public class WordComposer { - /** - * The list of unicode values for each keystroke (including surrounding keys) - */ - private ArrayList<int[]> mCodes; - - /** - * The word chosen from the candidate list, until it is committed. - */ - private String mPreferredWord; - - private StringBuilder mTypedWord; - - private int mCapsCount; - - private boolean mAutoCapitalized; - - /** - * Whether the user chose to capitalize the word. - */ - private boolean mIsCapitalized; - - WordComposer() { - mCodes = new ArrayList<int[]>(12); - mTypedWord = new StringBuilder(20); - } - - /** - * Clear out the keys registered so far. - */ - public void reset() { - mCodes.clear(); - mIsCapitalized = false; - mPreferredWord = null; - mTypedWord.setLength(0); - mCapsCount = 0; - } - - /** - * Number of keystrokes in the composing word. - * @return the number of keystrokes - */ - public int size() { - return mCodes.size(); - } - - /** - * Returns the codes at a particular position in the word. - * @param index the position in the word - * @return the unicode for the pressed and surrounding keys - */ - public int[] getCodesAt(int index) { - return mCodes.get(index); - } - - /** - * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of - * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. - * @param codes the array of unicode values - */ - public void add(int primaryCode, int[] codes) { - mTypedWord.append((char) primaryCode); - mCodes.add(codes); - if (Character.isUpperCase((char) primaryCode)) mCapsCount++; - } - - /** - * Delete the last keystroke as a result of hitting backspace. - */ - public void deleteLast() { - mCodes.remove(mCodes.size() - 1); - final int lastPos = mTypedWord.length() - 1; - char last = mTypedWord.charAt(lastPos); - mTypedWord.deleteCharAt(lastPos); - if (Character.isUpperCase(last)) mCapsCount--; - } - - /** - * Returns the word as it was typed, without any correction applied. - * @return the word that was typed so far - */ - public CharSequence getTypedWord() { - int wordSize = mCodes.size(); - if (wordSize == 0) { - return null; - } -// StringBuffer sb = new StringBuffer(wordSize); -// for (int i = 0; i < wordSize; i++) { -// char c = (char) mCodes.get(i)[0]; -// if (i == 0 && mIsCapitalized) { -// c = Character.toUpperCase(c); -// } -// sb.append(c); -// } -// return sb; - return mTypedWord; - } - - public void setCapitalized(boolean capitalized) { - mIsCapitalized = capitalized; - } - - /** - * Whether or not the user typed a capital letter as the first letter in the word - * @return capitalization preference - */ - public boolean isCapitalized() { - return mIsCapitalized; - } - - /** - * Stores the user's selected word, before it is actually committed to the text field. - * @param preferred - */ - public void setPreferredWord(String preferred) { - mPreferredWord = preferred; - } - - /** - * Return the word chosen by the user, or the typed word if no other word was chosen. - * @return the preferred word - */ - public CharSequence getPreferredWord() { - return mPreferredWord != null ? mPreferredWord : getTypedWord(); - } - - /** - * Returns true if more than one character is upper case, otherwise returns false. - */ - public boolean isMostlyCaps() { - return mCapsCount > 1; - } - - /** - * Saves the reason why the word is capitalized - whether it was automatic or - * due to the user hitting shift in the middle of a sentence. - * @param auto whether it was an automatic capitalization due to start of sentence - */ - public void setAutoCapitalized(boolean auto) { - mAutoCapitalized = auto; - } - - /** - * Returns whether the word was automatically capitalized. - * @return whether the word was automatically capitalized - */ - public boolean isAutoCapitalized() { - return mAutoCapitalized; - } -} diff --git a/src/com/android/inputmethod/voice/EditingUtil.java b/src/com/android/inputmethod/voice/EditingUtil.java deleted file mode 100644 index 6316d8ccf..000000000 --- a/src/com/android/inputmethod/voice/EditingUtil.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. - * - * 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.voice; - -import android.view.inputmethod.ExtractedText; -import android.view.inputmethod.ExtractedTextRequest; -import android.view.inputmethod.InputConnection; - -/** - * Utility methods to deal with editing text through an InputConnection. - */ -public class EditingUtil { - private EditingUtil() {}; - - /** - * Append newText to the text field represented by connection. - * The new text becomes selected. - */ - public static void appendText(InputConnection connection, String newText) { - if (connection == null) { - return; - } - - // Commit the composing text - connection.finishComposingText(); - - // Add a space if the field already has text. - CharSequence charBeforeCursor = connection.getTextBeforeCursor(1, 0); - if (charBeforeCursor != null - && !charBeforeCursor.equals(" ") - && (charBeforeCursor.length() > 0)) { - newText = " " + newText; - } - - connection.setComposingText(newText, 1); - } - - private static int getCursorPosition(InputConnection connection) { - ExtractedText extracted = connection.getExtractedText( - new ExtractedTextRequest(), 0); - if (extracted == null) { - return -1; - } - return extracted.startOffset + extracted.selectionStart; - } - - private static int getSelectionEnd(InputConnection connection) { - ExtractedText extracted = connection.getExtractedText( - new ExtractedTextRequest(), 0); - if (extracted == null) { - return -1; - } - return extracted.startOffset + extracted.selectionEnd; - } - - /** - * @param connection connection to the current text field. - * @param sep characters which may separate words - * @return the word that surrounds the cursor, including up to one trailing - * separator. For example, if the field contains "he|llo world", where | - * represents the cursor, then "hello " will be returned. - */ - public static String getWordAtCursor( - InputConnection connection, String separators) { - Range range = getWordRangeAtCursor(connection, separators); - return (range == null) ? null : range.word; - } - - /** - * Removes the word surrounding the cursor. Parameters are identical to - * getWordAtCursor. - */ - public static void deleteWordAtCursor( - InputConnection connection, String separators) { - - Range range = getWordRangeAtCursor(connection, separators); - if (range == null) return; - - connection.finishComposingText(); - // Move cursor to beginning of word, to avoid crash when cursor is outside - // of valid range after deleting text. - int newCursor = getCursorPosition(connection) - range.charsBefore; - connection.setSelection(newCursor, newCursor); - connection.deleteSurroundingText(0, range.charsBefore + range.charsAfter); - } - - /** - * Represents a range of text, relative to the current cursor position. - */ - private static class Range { - /** Characters before selection start */ - int charsBefore; - - /** - * Characters after selection start, including one trailing word - * separator. - */ - int charsAfter; - - /** The actual characters that make up a word */ - String word; - - public Range(int charsBefore, int charsAfter, String word) { - if (charsBefore < 0 || charsAfter < 0) { - throw new IndexOutOfBoundsException(); - } - this.charsBefore = charsBefore; - this.charsAfter = charsAfter; - this.word = word; - } - } - - private static Range getWordRangeAtCursor( - InputConnection connection, String sep) { - if (connection == null || sep == null) { - return null; - } - CharSequence before = connection.getTextBeforeCursor(1000, 0); - CharSequence after = connection.getTextAfterCursor(1000, 0); - if (before == null || after == null) { - return null; - } - - // Find first word separator before the cursor - int start = before.length(); - while (--start > 0 && !isWhitespace(before.charAt(start - 1), sep)); - - // Find last word separator after the cursor - int end = -1; - while (++end < after.length() && !isWhitespace(after.charAt(end), sep)); - if (end < after.length() - 1) { - end++; // Include trailing space, if it exists, in word - } - - int cursor = getCursorPosition(connection); - if (start >= 0 && cursor + end <= after.length() + before.length()) { - String word = before.toString().substring(start, before.length()) - + after.toString().substring(0, end); - return new Range(before.length() - start, end, word); - } - - return null; - } - - private static boolean isWhitespace(int code, String whitespace) { - return whitespace.contains(String.valueOf((char) code)); - } -} diff --git a/src/com/android/inputmethod/voice/FieldContext.java b/src/com/android/inputmethod/voice/FieldContext.java deleted file mode 100644 index 5fbacfb6c..000000000 --- a/src/com/android/inputmethod/voice/FieldContext.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. - * - * 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.voice; - -import android.os.Bundle; -import android.util.Log; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.ExtractedText; -import android.view.inputmethod.ExtractedTextRequest; -import android.view.inputmethod.InputConnection; - -/** - * Represents information about a given text field, which can be passed - * to the speech recognizer as context information. - */ -public class FieldContext { - private static final boolean DBG = false; - - static final String LABEL = "label"; - static final String HINT = "hint"; - static final String PACKAGE_NAME = "packageName"; - static final String FIELD_ID = "fieldId"; - static final String FIELD_NAME = "fieldName"; - static final String SINGLE_LINE = "singleLine"; - static final String INPUT_TYPE = "inputType"; - static final String IME_OPTIONS = "imeOptions"; - static final String SELECTED_LANGUAGE = "selectedLanguage"; - static final String ENABLED_LANGUAGES = "enabledLanguages"; - - Bundle mFieldInfo; - - public FieldContext(InputConnection conn, EditorInfo info, - String selectedLanguage, String[] enabledLanguages) { - mFieldInfo = new Bundle(); - addEditorInfoToBundle(info, mFieldInfo); - addInputConnectionToBundle(conn, mFieldInfo); - addLanguageInfoToBundle(selectedLanguage, enabledLanguages, mFieldInfo); - if (DBG) Log.i("FieldContext", "Bundle = " + mFieldInfo.toString()); - } - - private static String safeToString(Object o) { - if (o == null) { - return ""; - } - return o.toString(); - } - - private static void addEditorInfoToBundle(EditorInfo info, Bundle bundle) { - if (info == null) { - return; - } - - bundle.putString(LABEL, safeToString(info.label)); - bundle.putString(HINT, safeToString(info.hintText)); - bundle.putString(PACKAGE_NAME, safeToString(info.packageName)); - bundle.putInt(FIELD_ID, info.fieldId); - bundle.putString(FIELD_NAME, safeToString(info.fieldName)); - bundle.putInt(INPUT_TYPE, info.inputType); - bundle.putInt(IME_OPTIONS, info.imeOptions); - } - - private static void addInputConnectionToBundle( - InputConnection conn, Bundle bundle) { - if (conn == null) { - return; - } - - ExtractedText et = conn.getExtractedText(new ExtractedTextRequest(), 0); - if (et == null) { - return; - } - bundle.putBoolean(SINGLE_LINE, (et.flags & et.FLAG_SINGLE_LINE) > 0); - } - - private static void addLanguageInfoToBundle( - String selectedLanguage, String[] enabledLanguages, Bundle bundle) { - bundle.putString(SELECTED_LANGUAGE, selectedLanguage); - bundle.putStringArray(ENABLED_LANGUAGES, enabledLanguages); - } - - public Bundle getBundle() { - return mFieldInfo; - } - - public String toString() { - return mFieldInfo.toString(); - } -} diff --git a/src/com/android/inputmethod/voice/LatinIMEWithVoice.java b/src/com/android/inputmethod/voice/LatinIMEWithVoice.java deleted file mode 100644 index ccbf5b6bc..000000000 --- a/src/com/android/inputmethod/voice/LatinIMEWithVoice.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. - * - * 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.voice; - -import android.content.Intent; - -import com.android.inputmethod.latin.LatinIME; - -public class LatinIMEWithVoice extends LatinIME { - @Override - protected void launchSettings() { - launchSettings(LatinIMEWithVoiceSettings.class); - } -} diff --git a/src/com/android/inputmethod/voice/LatinIMEWithVoiceSettings.java b/src/com/android/inputmethod/voice/LatinIMEWithVoiceSettings.java deleted file mode 100644 index 13a58e14d..000000000 --- a/src/com/android/inputmethod/voice/LatinIMEWithVoiceSettings.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. - * - * 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.voice; - -import com.android.inputmethod.latin.LatinIMESettings; - -public class LatinIMEWithVoiceSettings extends LatinIMESettings {} diff --git a/src/com/android/inputmethod/voice/RecognitionView.java b/src/com/android/inputmethod/voice/RecognitionView.java deleted file mode 100644 index 1e99c3cf7..000000000 --- a/src/com/android/inputmethod/voice/RecognitionView.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. - * - * 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.voice; - -import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.ShortBuffer; -import java.util.ArrayList; -import java.util.List; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.CornerPathEffect; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PathEffect; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.util.TypedValue; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup.MarginLayoutParams; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; - -import com.android.inputmethod.latin.R; - -/** - * The user interface for the "Speak now" and "working" states. - * Displays a recognition dialog (with waveform, voice meter, etc.), - * plays beeps, shows errors, etc. - */ -public class RecognitionView { - private static final String TAG = "RecognitionView"; - - private Handler mUiHandler; // Reference to UI thread - private View mView; - private Context mContext; - - private ImageView mImage; - private TextView mText; - private View mButton; - private TextView mButtonText; - private View mProgress; - - private Drawable mInitializing; - private Drawable mError; - private List<Drawable> mSpeakNow; - - private float mVolume = 0.0f; - private int mLevel = 0; - - private enum State {LISTENING, WORKING, READY} - private State mState = State.READY; - - private float mMinMicrophoneLevel; - private float mMaxMicrophoneLevel; - - /** Updates the microphone icon to show user their volume.*/ - private Runnable mUpdateVolumeRunnable = new Runnable() { - public void run() { - if (mState != State.LISTENING) { - return; - } - - final float min = mMinMicrophoneLevel; - final float max = mMaxMicrophoneLevel; - final int maxLevel = mSpeakNow.size() - 1; - - int index = (int) ((mVolume - min) / (max - min) * maxLevel); - final int level = Math.min(Math.max(0, index), maxLevel); - - if (level != mLevel) { - mImage.setImageDrawable(mSpeakNow.get(level)); - mLevel = level; - } - mUiHandler.postDelayed(mUpdateVolumeRunnable, 50); - } - }; - - public RecognitionView(Context context, OnClickListener clickListener) { - mUiHandler = new Handler(); - - LayoutInflater inflater = (LayoutInflater) context.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - mView = inflater.inflate(R.layout.recognition_status, null); - ContentResolver cr = context.getContentResolver(); - mMinMicrophoneLevel = SettingsUtil.getSettingsFloat( - cr, SettingsUtil.LATIN_IME_MIN_MICROPHONE_LEVEL, 15.f); - mMaxMicrophoneLevel = SettingsUtil.getSettingsFloat( - cr, SettingsUtil.LATIN_IME_MAX_MICROPHONE_LEVEL, 30.f); - - // Pre-load volume level images - Resources r = context.getResources(); - - mSpeakNow = new ArrayList<Drawable>(); - mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level0)); - mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level1)); - mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level2)); - mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level3)); - mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level4)); - mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level5)); - mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level6)); - - mInitializing = r.getDrawable(R.drawable.mic_slash); - mError = r.getDrawable(R.drawable.caution); - - mImage = (ImageView) mView.findViewById(R.id.image); - mButton = mView.findViewById(R.id.button); - mButton.setOnClickListener(clickListener); - mText = (TextView) mView.findViewById(R.id.text); - mButtonText = (TextView) mView.findViewById(R.id.button_text); - mProgress = mView.findViewById(R.id.progress); - - mContext = context; - } - - public View getView() { - return mView; - } - - public void restoreState() { - mUiHandler.post(new Runnable() { - public void run() { - // Restart the spinner - if (mState == State.WORKING) { - ((ProgressBar)mProgress).setIndeterminate(false); - ((ProgressBar)mProgress).setIndeterminate(true); - } - } - }); - } - - public void showInitializing() { - mUiHandler.post(new Runnable() { - public void run() { - prepareDialog(false, mContext.getText(R.string.voice_initializing), mInitializing, - mContext.getText(R.string.cancel)); - } - }); - } - - public void showListening() { - mUiHandler.post(new Runnable() { - public void run() { - mState = State.LISTENING; - prepareDialog(false, mContext.getText(R.string.voice_listening), mSpeakNow.get(0), - mContext.getText(R.string.cancel)); - } - }); - mUiHandler.postDelayed(mUpdateVolumeRunnable, 50); - } - - public void updateVoiceMeter(final float rmsdB) { - mVolume = rmsdB; - } - - public void showError(final String message) { - mUiHandler.post(new Runnable() { - public void run() { - mState = State.READY; - prepareDialog(false, message, mError, mContext.getText(R.string.ok)); - } - }); - } - - public void showWorking( - final ByteArrayOutputStream waveBuffer, - final int speechStartPosition, - final int speechEndPosition) { - - mUiHandler.post(new Runnable() { - public void run() { - mState = State.WORKING; - prepareDialog(true, mContext.getText(R.string.voice_working), null, mContext - .getText(R.string.cancel)); - final ShortBuffer buf = ByteBuffer.wrap(waveBuffer.toByteArray()).order( - ByteOrder.nativeOrder()).asShortBuffer(); - buf.position(0); - waveBuffer.reset(); - showWave(buf, speechStartPosition / 2, speechEndPosition / 2); - } - }); - } - - private void prepareDialog(boolean spinVisible, CharSequence text, Drawable image, - CharSequence btnTxt) { - if (spinVisible) { - mProgress.setVisibility(View.VISIBLE); - mImage.setVisibility(View.GONE); - } else { - mProgress.setVisibility(View.GONE); - mImage.setImageDrawable(image); - mImage.setVisibility(View.VISIBLE); - } - mText.setText(text); - mButtonText.setText(btnTxt); - } - - /** - * @return an average abs of the specified buffer. - */ - private static int getAverageAbs(ShortBuffer buffer, int start, int i, int npw) { - int from = start + i * npw; - int end = from + npw; - int total = 0; - for (int x = from; x < end; x++) { - total += Math.abs(buffer.get(x)); - } - return total / npw; - } - - - /** - * Shows waveform of input audio. - * - * Copied from version in VoiceSearch's RecognitionActivity. - * - * TODO: adjust stroke width based on the size of data. - * TODO: use dip rather than pixels. - */ - private void showWave(ShortBuffer waveBuffer, int startPosition, int endPosition) { - final int w = ((View) mImage.getParent()).getWidth(); - final int h = mImage.getHeight(); - if (w <= 0 || h <= 0) { - // view is not visible this time. Skip drawing. - return; - } - final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - final Canvas c = new Canvas(b); - final Paint paint = new Paint(); - paint.setColor(0xFFFFFFFF); // 0xAARRGGBB - paint.setAntiAlias(true); - paint.setStyle(Paint.Style.STROKE); - paint.setAlpha(0x90); - - final PathEffect effect = new CornerPathEffect(3); - paint.setPathEffect(effect); - - final int numSamples = waveBuffer.remaining(); - int endIndex; - if (endPosition == 0) { - endIndex = numSamples; - } else { - endIndex = Math.min(endPosition, numSamples); - } - - int startIndex = startPosition - 2000; // include 250ms before speech - if (startIndex < 0) { - startIndex = 0; - } - final int numSamplePerWave = 200; // 8KHz 25ms = 200 samples - final float scale = 10.0f / 65536.0f; - - final int count = (endIndex - startIndex) / numSamplePerWave; - final float deltaX = 1.0f * w / count; - int yMax = h / 2 - 10; - Path path = new Path(); - c.translate(0, yMax); - float x = 0; - path.moveTo(x, 0); - yMax -= 10; - for (int i = 0; i < count; i++) { - final int avabs = getAverageAbs(waveBuffer, startIndex, i , numSamplePerWave); - int sign = ( (i & 01) == 0) ? -1 : 1; - final float y = Math.min(yMax, avabs * h * scale) * sign; - path.lineTo(x, y); - x += deltaX; - path.lineTo(x, y); - } - if (deltaX > 4) { - paint.setStrokeWidth(3); - } else { - paint.setStrokeWidth(Math.max(1, (int) (deltaX -.05))); - } - c.drawPath(path, paint); - mImage.setImageBitmap(b); - mImage.setVisibility(View.VISIBLE); - MarginLayoutParams mProgressParams = (MarginLayoutParams)mProgress.getLayoutParams(); - mProgressParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, - -h / 2 - 18, mContext.getResources().getDisplayMetrics()); - - // Tweak the padding manually to fill out the whole view horizontally. - // TODO: Do this in the xml layout instead. - ((View) mImage.getParent()).setPadding(4, ((View) mImage.getParent()).getPaddingTop(), 3, - ((View) mImage.getParent()).getPaddingBottom()); - mProgress.setLayoutParams(mProgressParams); - } - - - public void finish() { - mUiHandler.post(new Runnable() { - public void run() { - mState = State.READY; - exitWorking(); - } - }); - } - - private void exitWorking() { - mProgress.setVisibility(View.GONE); - mImage.setVisibility(View.VISIBLE); - } -} diff --git a/src/com/android/inputmethod/voice/SettingsUtil.java b/src/com/android/inputmethod/voice/SettingsUtil.java deleted file mode 100644 index abf52047f..000000000 --- a/src/com/android/inputmethod/voice/SettingsUtil.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. - * - * 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.voice; - -import android.content.ContentResolver; -import android.database.Cursor; -import android.net.Uri; -import android.provider.Settings; -import android.util.Log; - -/** - * Utility for retrieving settings from Settings.Secure. - */ -public class SettingsUtil { - /** - * A whitespace-separated list of supported locales for voice input from the keyboard. - */ - public static final String LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES = - "latin_ime_voice_input_supported_locales"; - - /** - * A whitespace-separated list of recommended app packages for voice input from the - * keyboard. - */ - public static final String LATIN_IME_VOICE_INPUT_RECOMMENDED_PACKAGES = - "latin_ime_voice_input_recommended_packages"; - - /** - * The maximum number of unique days to show the swipe hint for voice input. - */ - public static final String LATIN_IME_VOICE_INPUT_SWIPE_HINT_MAX_DAYS = - "latin_ime_voice_input_swipe_hint_max_days"; - - /** - * The maximum number of times to show the punctuation hint for voice input. - */ - public static final String LATIN_IME_VOICE_INPUT_PUNCTUATION_HINT_MAX_DISPLAYS = - "latin_ime_voice_input_punctuation_hint_max_displays"; - - /** - * Endpointer parameters for voice input from the keyboard. - */ - public static final String LATIN_IME_SPEECH_MINIMUM_LENGTH_MILLIS = - "latin_ime_speech_minimum_length_millis"; - public static final String LATIN_IME_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS = - "latin_ime_speech_input_complete_silence_length_millis"; - public static final String LATIN_IME_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS = - "latin_ime_speech_input_possibly_complete_silence_length_millis"; - - /** - * Min and max volume levels that can be displayed on the "speak now" screen. - */ - public static final String LATIN_IME_MIN_MICROPHONE_LEVEL = - "latin_ime_min_microphone_level"; - public static final String LATIN_IME_MAX_MICROPHONE_LEVEL = - "latin_ime_max_microphone_level"; - - /** - * The number of sentence-level alternates to request of the server. - */ - public static final String LATIN_IME_MAX_VOICE_RESULTS = "latin_ime_max_voice_results"; - - /** - * Get a string-valued setting. - * - * @param cr The content resolver to use - * @param key The setting to look up - * @param defaultValue The default value to use if none can be found - * @return The value of the setting, or defaultValue if it couldn't be found - */ - public static String getSettingsString(ContentResolver cr, String key, String defaultValue) { - String result = Settings.Secure.getString(cr, key); - return (result == null) ? defaultValue : result; - } - - /** - * Get an int-valued setting. - * - * @param cr The content resolver to use - * @param key The setting to look up - * @param defaultValue The default value to use if the setting couldn't be found or parsed - * @return The value of the setting, or defaultValue if it couldn't be found or parsed - */ - public static int getSettingsInt(ContentResolver cr, String key, int defaultValue) { - return Settings.Secure.getInt(cr, key, defaultValue); - } - - /** - * Get a float-valued setting. - * - * @param cr The content resolver to use - * @param key The setting to look up - * @param defaultValue The default value to use if the setting couldn't be found or parsed - * @return The value of the setting, or defaultValue if it couldn't be found or parsed - */ - public static float getSettingsFloat(ContentResolver cr, String key, float defaultValue) { - return Settings.Secure.getFloat(cr, key, defaultValue); - } -} diff --git a/src/com/android/inputmethod/voice/VoiceInput.java b/src/com/android/inputmethod/voice/VoiceInput.java deleted file mode 100644 index e881856dd..000000000 --- a/src/com/android/inputmethod/voice/VoiceInput.java +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. - * - * 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.voice; - -import com.android.inputmethod.latin.R; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.speech.RecognitionListener; -import android.speech.RecognitionManager; -import android.speech.RecognizerIntent; -import android.util.Log; -import android.view.View; -import android.view.View.OnClickListener; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -/** - * Speech recognition input, including both user interface and a background - * process to stream audio to the network recognizer. This class supplies a - * View (getView()), which it updates as recognition occurs. The user of this - * class is responsible for making the view visible to the user, as well as - * handling various events returned through UiListener. - */ -public class VoiceInput implements OnClickListener { - private static final String TAG = "VoiceInput"; - private static final String EXTRA_RECOGNITION_CONTEXT = - "android.speech.extras.RECOGNITION_CONTEXT"; - private static final String EXTRA_CALLING_PACKAGE = "calling_package"; - - private static final String DEFAULT_RECOMMENDED_PACKAGES = - "com.android.mms " + - "com.google.android.gm " + - "com.google.android.talk " + - "com.google.android.apps.googlevoice " + - "com.android.email " + - "com.android.browser "; - - // WARNING! Before enabling this, fix the problem with calling getExtractedText() in - // landscape view. It causes Extracted text updates to be rejected due to a token mismatch - public static boolean ENABLE_WORD_CORRECTIONS = false; - - // Dummy word suggestion which means "delete current word" - public static final String DELETE_SYMBOL = " \u00D7 "; // times symbol - - private Whitelist mRecommendedList; - private Whitelist mBlacklist; - - private VoiceInputLogger mLogger; - - // Names of a few intent extras defined in VoiceSearch's RecognitionService. - // These let us tweak the endpointer parameters. - private static final String EXTRA_SPEECH_MINIMUM_LENGTH_MILLIS = - "android.speech.extras.SPEECH_INPUT_MINIMUM_LENGTH_MILLIS"; - private static final String EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS = - "android.speech.extras.SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS"; - private static final String EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS = - "android.speech.extras.SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS"; - - // The usual endpointer default value for input complete silence length is 0.5 seconds, - // but that's used for things like voice search. For dictation-like voice input like this, - // we go with a more liberal value of 1 second. This value will only be used if a value - // is not provided from Gservices. - private static final String INPUT_COMPLETE_SILENCE_LENGTH_DEFAULT_VALUE_MILLIS = "1000"; - - // Used to record part of that state for logging purposes. - public static final int DEFAULT = 0; - public static final int LISTENING = 1; - public static final int WORKING = 2; - public static final int ERROR = 3; - - private int mState = DEFAULT; - - private final static int MSG_CLOSE_ERROR_DIALOG = 1; - - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - if (msg.what == MSG_CLOSE_ERROR_DIALOG) { - mState = DEFAULT; - mRecognitionView.finish(); - mUiListener.onCancelVoice(); - } - } - }; - - /** - * Events relating to the recognition UI. You must implement these. - */ - public interface UiListener { - - /** - * @param recognitionResults a set of transcripts for what the user - * spoke, sorted by likelihood. - */ - public void onVoiceResults( - List<String> recognitionResults, - Map<String, List<CharSequence>> alternatives); - - /** - * Called when the user cancels speech recognition. - */ - public void onCancelVoice(); - } - - private RecognitionManager mRecognitionManager; - private RecognitionListener mRecognitionListener; - private RecognitionView mRecognitionView; - private UiListener mUiListener; - private Context mContext; - - /** - * @param context the service or activity in which we're running. - * @param uiHandler object to receive events from VoiceInput. - */ - public VoiceInput(Context context, UiListener uiHandler) { - mLogger = VoiceInputLogger.getLogger(context); - mRecognitionListener = new ImeRecognitionListener(); - mRecognitionManager = RecognitionManager.createRecognitionManager(context); - mRecognitionManager.setRecognitionListener(mRecognitionListener); - mUiListener = uiHandler; - mContext = context; - newView(); - - String recommendedPackages = SettingsUtil.getSettingsString( - context.getContentResolver(), - SettingsUtil.LATIN_IME_VOICE_INPUT_RECOMMENDED_PACKAGES, - DEFAULT_RECOMMENDED_PACKAGES); - - mRecommendedList = new Whitelist(); - for (String recommendedPackage : recommendedPackages.split("\\s+")) { - mRecommendedList.addApp(recommendedPackage); - } - - mBlacklist = new Whitelist(); - mBlacklist.addApp("com.android.setupwizard"); - } - - /** - * The configuration of the IME changed and may have caused the views to be layed out - * again. Restore the state of the recognition view. - */ - public void onConfigurationChanged() { - mRecognitionView.restoreState(); - } - - /** - * @return true if field is blacklisted for voice - */ - public boolean isBlacklistedField(FieldContext context) { - return mBlacklist.matches(context); - } - - /** - * Used to decide whether to show voice input hints for this field, etc. - * - * @return true if field is recommended for voice - */ - public boolean isRecommendedField(FieldContext context) { - return mRecommendedList.matches(context); - } - - /** - * Start listening for speech from the user. This will grab the microphone - * and start updating the view provided by getView(). It is the caller's - * responsibility to ensure that the view is visible to the user at this stage. - * - * @param context the same FieldContext supplied to voiceIsEnabled() - * @param swipe whether this voice input was started by swipe, for logging purposes - */ - public void startListening(FieldContext context, boolean swipe) { - mState = DEFAULT; - - Locale locale = Locale.getDefault(); - String localeString = locale.getLanguage() + "-" + locale.getCountry(); - - mLogger.start(localeString, swipe); - - mState = LISTENING; - - mRecognitionView.showInitializing(); - startListeningAfterInitialization(context); - } - - /** - * Called only when the recognition manager's initialization completed - * - * @param context context with which {@link #startListening(FieldContext, boolean)} was executed - */ - private void startListeningAfterInitialization(FieldContext context) { - Intent intent = makeIntent(); - intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, ""); - intent.putExtra(EXTRA_RECOGNITION_CONTEXT, context.getBundle()); - intent.putExtra(EXTRA_CALLING_PACKAGE, "VoiceIME"); - intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, - SettingsUtil.getSettingsInt( - mContext.getContentResolver(), - SettingsUtil.LATIN_IME_MAX_VOICE_RESULTS, - 1)); - - // Get endpointer params from Gservices. - // TODO: Consider caching these values for improved performance on slower devices. - final ContentResolver cr = mContext.getContentResolver(); - putEndpointerExtra( - cr, - intent, - SettingsUtil.LATIN_IME_SPEECH_MINIMUM_LENGTH_MILLIS, - EXTRA_SPEECH_MINIMUM_LENGTH_MILLIS, - null /* rely on endpointer default */); - putEndpointerExtra( - cr, - intent, - SettingsUtil.LATIN_IME_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS, - EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS, - INPUT_COMPLETE_SILENCE_LENGTH_DEFAULT_VALUE_MILLIS - /* our default value is different from the endpointer's */); - putEndpointerExtra( - cr, - intent, - SettingsUtil. - LATIN_IME_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, - EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, - null /* rely on endpointer default */); - - mRecognitionManager.startListening(intent); - } - - /** - * Gets the value of the provided Gservices key, attempts to parse it into a long, - * and if successful, puts the long value as an extra in the provided intent. - */ - private void putEndpointerExtra(ContentResolver cr, Intent i, - String gservicesKey, String intentExtraKey, String defaultValue) { - long l = -1; - String s = SettingsUtil.getSettingsString(cr, gservicesKey, defaultValue); - if (s != null) { - try { - l = Long.valueOf(s); - } catch (NumberFormatException e) { - Log.e(TAG, "could not parse value for " + gservicesKey + ": " + s); - } - } - - if (l != -1) i.putExtra(intentExtraKey, l); - } - - public void destroy() { - mRecognitionManager.destroy(); - } - - /** - * Creates a new instance of the view that is returned by {@link #getView()} - * Clients should use this when a previously returned view is stuck in a - * layout that is being thrown away and a new one is need to show to the - * user. - */ - public void newView() { - mRecognitionView = new RecognitionView(mContext, this); - } - - /** - * @return a view that shows the recognition flow--e.g., "Speak now" and - * "working" dialogs. - */ - public View getView() { - return mRecognitionView.getView(); - } - - /** - * Handle the cancel button. - */ - public void onClick(View view) { - switch(view.getId()) { - case R.id.button: - cancel(); - break; - } - } - - public void logTextModified() { - mLogger.textModified(); - } - - public void logKeyboardWarningDialogShown() { - mLogger.keyboardWarningDialogShown(); - } - - public void logKeyboardWarningDialogDismissed() { - mLogger.keyboardWarningDialogDismissed(); - } - - public void logKeyboardWarningDialogOk() { - mLogger.keyboardWarningDialogOk(); - } - - public void logKeyboardWarningDialogCancel() { - mLogger.keyboardWarningDialogCancel(); - } - - public void logSwipeHintDisplayed() { - mLogger.swipeHintDisplayed(); - } - - public void logPunctuationHintDisplayed() { - mLogger.punctuationHintDisplayed(); - } - - public void logVoiceInputDelivered() { - mLogger.voiceInputDelivered(); - } - - public void logNBestChoose(int index) { - mLogger.nBestChoose(index); - } - - public void logInputEnded() { - mLogger.inputEnded(); - } - - public void flushLogs() { - mLogger.flush(); - } - - private static Intent makeIntent() { - Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); - - // On Cupcake, use VoiceIMEHelper since VoiceSearch doesn't support. - // On Donut, always use VoiceSearch, since VoiceIMEHelper and - // VoiceSearch may conflict. - if (Build.VERSION.RELEASE.equals("1.5")) { - intent = intent.setClassName( - "com.google.android.voiceservice", - "com.google.android.voiceservice.IMERecognitionService"); - } else { - intent = intent.setClassName( - "com.google.android.voicesearch", - "com.google.android.voicesearch.RecognitionService"); - } - - return intent; - } - - /** - * Cancel in-progress speech recognition. - */ - public void cancel() { - switch (mState) { - case LISTENING: - mLogger.cancelDuringListening(); - break; - case WORKING: - mLogger.cancelDuringWorking(); - break; - case ERROR: - mLogger.cancelDuringError(); - break; - } - mState = DEFAULT; - - // Remove all pending tasks (e.g., timers to cancel voice input) - mHandler.removeMessages(MSG_CLOSE_ERROR_DIALOG); - - mRecognitionManager.cancel(); - mUiListener.onCancelVoice(); - mRecognitionView.finish(); - } - - private int getErrorStringId(int errorType, boolean endpointed) { - switch (errorType) { - // We use CLIENT_ERROR to signify that voice search is not available on the device. - case RecognitionManager.ERROR_CLIENT: - return R.string.voice_not_installed; - case RecognitionManager.ERROR_NETWORK: - return R.string.voice_network_error; - case RecognitionManager.ERROR_NETWORK_TIMEOUT: - return endpointed ? - R.string.voice_network_error : R.string.voice_too_much_speech; - case RecognitionManager.ERROR_AUDIO: - return R.string.voice_audio_error; - case RecognitionManager.ERROR_SERVER: - return R.string.voice_server_error; - case RecognitionManager.ERROR_SPEECH_TIMEOUT: - return R.string.voice_speech_timeout; - case RecognitionManager.ERROR_NO_MATCH: - return R.string.voice_no_match; - default: return R.string.voice_error; - } - } - - private void onError(int errorType, boolean endpointed) { - Log.i(TAG, "error " + errorType); - mLogger.error(errorType); - onError(mContext.getString(getErrorStringId(errorType, endpointed))); - } - - private void onError(String error) { - mState = ERROR; - mRecognitionView.showError(error); - // Wait a couple seconds and then automatically dismiss message. - mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_CLOSE_ERROR_DIALOG), 2000); - } - - private class ImeRecognitionListener implements RecognitionListener { - // Waveform data - final ByteArrayOutputStream mWaveBuffer = new ByteArrayOutputStream(); - int mSpeechStart; - private boolean mEndpointed = false; - - public void onReadyForSpeech(Bundle noiseParams) { - mRecognitionView.showListening(); - } - - public void onBeginningOfSpeech() { - mEndpointed = false; - mSpeechStart = mWaveBuffer.size(); - } - - public void onRmsChanged(float rmsdB) { - mRecognitionView.updateVoiceMeter(rmsdB); - } - - public void onBufferReceived(byte[] buf) { - try { - mWaveBuffer.write(buf); - } catch (IOException e) {} - } - - public void onEndOfSpeech() { - mEndpointed = true; - mState = WORKING; - mRecognitionView.showWorking(mWaveBuffer, mSpeechStart, mWaveBuffer.size()); - } - - public void onError(int errorType) { - mState = ERROR; - VoiceInput.this.onError(errorType, mEndpointed); - } - - public void onResults(Bundle resultsBundle) { - List<String> results = resultsBundle - .getStringArrayList(RecognitionManager.RESULTS_RECOGNITION); - mState = DEFAULT; - - final Map<String, List<CharSequence>> alternatives = - new HashMap<String, List<CharSequence>>(); - if (results.size() >= 2 && ENABLE_WORD_CORRECTIONS) { - final String[][] words = new String[results.size()][]; - for (int i = 0; i < words.length; i++) { - words[i] = results.get(i).split(" "); - } - - for (int key = 0; key < words[0].length; key++) { - alternatives.put(words[0][key], new ArrayList<CharSequence>()); - for (int alt = 1; alt < words.length; alt++) { - int keyBegin = key * words[alt].length / words[0].length; - int keyEnd = (key + 1) * words[alt].length / words[0].length; - - for (int i = keyBegin; i < Math.min(words[alt].length, keyEnd); i++) { - List<CharSequence> altList = alternatives.get(words[0][key]); - if (!altList.contains(words[alt][i]) && altList.size() < 6) { - altList.add(words[alt][i]); - } - } - } - } - } - - if (results.size() > 5) { - results = results.subList(0, 5); - } - mUiListener.onVoiceResults(results, alternatives); - mRecognitionView.finish(); - } - - public void onPartialResults(final Bundle partialResults) { - // currently - do nothing - } - - public void onEvent(int eventType, Bundle params) { - // do nothing - reserved for events that might be added in the future - } - } -} diff --git a/src/com/android/inputmethod/voice/VoiceInputLogger.java b/src/com/android/inputmethod/voice/VoiceInputLogger.java deleted file mode 100644 index 659033340..000000000 --- a/src/com/android/inputmethod/voice/VoiceInputLogger.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2008 Google Inc. - * - * 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.voice; - -import com.android.common.speech.LoggingEvents; - -import android.content.Context; -import android.content.Intent; - -/** - * Provides the logging facility for voice input events. This fires broadcasts back to - * the voice search app which then logs on our behalf. - * - * Note that debug console logging does not occur in this class. If you want to - * see console output of these logging events, there is a boolean switch to turn - * on on the VoiceSearch side. - */ -public class VoiceInputLogger { - private static final String TAG = VoiceInputLogger.class.getSimpleName(); - - private static VoiceInputLogger sVoiceInputLogger; - - private final Context mContext; - - // The base intent used to form all broadcast intents to the logger - // in VoiceSearch. - private final Intent mBaseIntent; - - /** - * Returns the singleton of the logger. - * - * @param contextHint a hint context used when creating the logger instance. - * Ignored if the singleton instance already exists. - */ - public static synchronized VoiceInputLogger getLogger(Context contextHint) { - if (sVoiceInputLogger == null) { - sVoiceInputLogger = new VoiceInputLogger(contextHint); - } - return sVoiceInputLogger; - } - - public VoiceInputLogger(Context context) { - mContext = context; - - mBaseIntent = new Intent(LoggingEvents.ACTION_LOG_EVENT); - mBaseIntent.putExtra(LoggingEvents.EXTRA_APP_NAME, LoggingEvents.VoiceIme.APP_NAME); - } - - private Intent newLoggingBroadcast(int event) { - Intent i = new Intent(mBaseIntent); - i.putExtra(LoggingEvents.EXTRA_EVENT, event); - return i; - } - - public void flush() { - Intent i = new Intent(mBaseIntent); - i.putExtra(LoggingEvents.EXTRA_FLUSH, true); - mContext.sendBroadcast(i); - } - - public void keyboardWarningDialogShown() { - mContext.sendBroadcast(newLoggingBroadcast( - LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_SHOWN)); - } - - public void keyboardWarningDialogDismissed() { - mContext.sendBroadcast(newLoggingBroadcast( - LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_DISMISSED)); - } - - public void keyboardWarningDialogOk() { - mContext.sendBroadcast(newLoggingBroadcast( - LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_OK)); - } - - public void keyboardWarningDialogCancel() { - mContext.sendBroadcast(newLoggingBroadcast( - LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_CANCEL)); - } - - public void settingsWarningDialogShown() { - mContext.sendBroadcast(newLoggingBroadcast( - LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_SHOWN)); - } - - public void settingsWarningDialogDismissed() { - mContext.sendBroadcast(newLoggingBroadcast( - LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_DISMISSED)); - } - - public void settingsWarningDialogOk() { - mContext.sendBroadcast(newLoggingBroadcast( - LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_OK)); - } - - public void settingsWarningDialogCancel() { - mContext.sendBroadcast(newLoggingBroadcast( - LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_CANCEL)); - } - - public void swipeHintDisplayed() { - mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.SWIPE_HINT_DISPLAYED)); - } - - public void cancelDuringListening() { - mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.CANCEL_DURING_LISTENING)); - } - - public void cancelDuringWorking() { - mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.CANCEL_DURING_WORKING)); - } - - public void cancelDuringError() { - mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.CANCEL_DURING_ERROR)); - } - - public void punctuationHintDisplayed() { - mContext.sendBroadcast(newLoggingBroadcast( - LoggingEvents.VoiceIme.PUNCTUATION_HINT_DISPLAYED)); - } - - public void error(int code) { - Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.ERROR); - i.putExtra(LoggingEvents.VoiceIme.EXTRA_ERROR_CODE, code); - mContext.sendBroadcast(i); - } - - public void start(String locale, boolean swipe) { - Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.START); - i.putExtra(LoggingEvents.VoiceIme.EXTRA_START_LOCALE, locale); - i.putExtra(LoggingEvents.VoiceIme.EXTRA_START_SWIPE, swipe); - i.putExtra(LoggingEvents.EXTRA_TIMESTAMP, System.currentTimeMillis()); - mContext.sendBroadcast(i); - } - - public void voiceInputDelivered() { - mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.VOICE_INPUT_DELIVERED)); - } - - public void textModified() { - mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED)); - } - - public void nBestChoose(int index) { - Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.N_BEST_CHOOSE); - i.putExtra(LoggingEvents.VoiceIme.EXTRA_N_BEST_CHOOSE_INDEX, index); - mContext.sendBroadcast(i); - } - - public void inputEnded() { - mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.INPUT_ENDED)); - } - - public void voiceInputSettingEnabled() { - mContext.sendBroadcast(newLoggingBroadcast( - LoggingEvents.VoiceIme.VOICE_INPUT_SETTING_ENABLED)); - } - - public void voiceInputSettingDisabled() { - mContext.sendBroadcast(newLoggingBroadcast( - LoggingEvents.VoiceIme.VOICE_INPUT_SETTING_DISABLED)); - } -} diff --git a/src/com/android/inputmethod/voice/WaveformImage.java b/src/com/android/inputmethod/voice/WaveformImage.java deleted file mode 100644 index 08d87c8f3..000000000 --- a/src/com/android/inputmethod/voice/WaveformImage.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2008-2009 Google Inc. - * - * 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.voice; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; - -import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.ShortBuffer; - -/** - * Utility class to draw a waveform into a bitmap, given a byte array - * that represents the waveform as a sequence of 16-bit integers. - * Adapted from RecognitionActivity.java. - */ -public class WaveformImage { - private static final int SAMPLING_RATE = 8000; - - private WaveformImage() {} - - public static Bitmap drawWaveform( - ByteArrayOutputStream waveBuffer, int w, int h, int start, int end) { - final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - final Canvas c = new Canvas(b); - final Paint paint = new Paint(); - paint.setColor(0xFFFFFFFF); // 0xRRGGBBAA - paint.setAntiAlias(true); - paint.setStrokeWidth(0); - - final ShortBuffer buf = ByteBuffer - .wrap(waveBuffer.toByteArray()) - .order(ByteOrder.nativeOrder()) - .asShortBuffer(); - buf.position(0); - - final int numSamples = waveBuffer.size() / 2; - final int delay = (SAMPLING_RATE * 100 / 1000); - int endIndex = end / 2 + delay; - if (end == 0 || endIndex >= numSamples) { - endIndex = numSamples; - } - int index = start / 2 - delay; - if (index < 0) { - index = 0; - } - final int size = endIndex - index; - int numSamplePerPixel = 32; - int delta = size / (numSamplePerPixel * w); - if (delta == 0) { - numSamplePerPixel = size / w; - delta = 1; - } - - final float scale = 3.5f / 65536.0f; - // do one less column to make sure we won't read past - // the buffer. - try { - for (int i = 0; i < w - 1 ; i++) { - final float x = i; - for (int j = 0; j < numSamplePerPixel; j++) { - final short s = buf.get(index); - final float y = (h / 2) - (s * h * scale); - c.drawPoint(x, y, paint); - index += delta; - } - } - } catch (IndexOutOfBoundsException e) { - // this can happen, but we don't care - } - - return b; - } -} diff --git a/src/com/android/inputmethod/voice/Whitelist.java b/src/com/android/inputmethod/voice/Whitelist.java deleted file mode 100644 index 167b688ca..000000000 --- a/src/com/android/inputmethod/voice/Whitelist.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. - * - * 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.voice; - -import android.os.Bundle; -import java.util.ArrayList; -import java.util.List; - -/** - * A set of text fields where speech has been explicitly enabled. - */ -public class Whitelist { - private List<Bundle> mConditions; - - public Whitelist() { - mConditions = new ArrayList<Bundle>(); - } - - public Whitelist(List<Bundle> conditions) { - this.mConditions = conditions; - } - - public void addApp(String app) { - Bundle bundle = new Bundle(); - bundle.putString("packageName", app); - mConditions.add(bundle); - } - - /** - * @return true if the field is a member of the whitelist. - */ - public boolean matches(FieldContext context) { - for (Bundle condition : mConditions) { - if (matches(condition, context.getBundle())) { - return true; - } - } - return false; - } - - /** - * @return true of all values in condition are matched by a value - * in target. - */ - private boolean matches(Bundle condition, Bundle target) { - for (String key : condition.keySet()) { - if (!condition.getString(key).equals(target.getString(key))) { - return false; - } - } - return true; - } -} diff --git a/src/com/google/android/voicesearch/LatinIMEWithVoice.java b/src/com/google/android/voicesearch/LatinIMEWithVoice.java deleted file mode 100644 index 8a339d14a..000000000 --- a/src/com/google/android/voicesearch/LatinIMEWithVoice.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * - * Copyright (C) 2009 Google Inc. - * - * 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.google.android.voicesearch; - -import android.content.Intent; - -import com.android.inputmethod.latin.LatinIME; - -public class LatinIMEWithVoice extends LatinIME { - @Override - protected void launchSettings() { - launchSettings(LatinIMEWithVoiceSettings.class); - } -} diff --git a/src/com/google/android/voicesearch/LatinIMEWithVoiceSettings.java b/src/com/google/android/voicesearch/LatinIMEWithVoiceSettings.java deleted file mode 100644 index a53cebfd9..000000000 --- a/src/com/google/android/voicesearch/LatinIMEWithVoiceSettings.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.google.android.voicesearch; - -import com.android.inputmethod.latin.LatinIMESettings; - -public class LatinIMEWithVoiceSettings extends LatinIMESettings {} |