aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod
diff options
context:
space:
mode:
authorsatok <satok@google.com>2011-01-19 03:34:48 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-01-19 03:34:48 -0800
commitb7b83125544964bf128e07456edfd0170d889dc4 (patch)
treef508770da496b7969baed44975ee58fee9b81206 /java/src/com/android/inputmethod
parent7a614e9439c0ca752072bd357010517985cb9955 (diff)
parent9c383385d5fb82496d7e7ca57826fc21ec8a6bbd (diff)
downloadlatinime-b7b83125544964bf128e07456edfd0170d889dc4.tar.gz
latinime-b7b83125544964bf128e07456edfd0170d889dc4.tar.xz
latinime-b7b83125544964bf128e07456edfd0170d889dc4.zip
Merge "Merge remote branch 'goog/master' into merge" into froyo-ub-latinimegoogle
Diffstat (limited to 'java/src/com/android/inputmethod')
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardShiftState.java50
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java35
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java17
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboard.java57
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java12
-rw-r--r--java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java2
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java34
-rw-r--r--java/src/com/android/inputmethod/latin/CandidateView.java24
-rw-r--r--java/src/com/android/inputmethod/latin/InputLanguageSelection.java2
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java262
-rw-r--r--java/src/com/android/inputmethod/latin/Settings.java51
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeLocale.java46
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeSwitcher.java66
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java33
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java2
-rw-r--r--java/src/com/android/inputmethod/latin/Utils.java25
-rw-r--r--java/src/com/android/inputmethod/voice/RecognitionView.java219
-rw-r--r--java/src/com/android/inputmethod/voice/SoundIndicator.java155
-rw-r--r--java/src/com/android/inputmethod/voice/VoiceIMEConnector.java145
-rw-r--r--java/src/com/android/inputmethod/voice/VoiceInput.java13
21 files changed, 876 insertions, 378 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index ae1d302db..863421f18 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -330,6 +330,10 @@ public class Keyboard {
return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCase();
}
+ public boolean isManualTemporaryUpperCaseFromAuto() {
+ return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCaseFromAuto();
+ }
+
public KeyboardShiftState getKeyboardShiftState() {
return mShiftState;
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardShiftState.java b/java/src/com/android/inputmethod/keyboard/KeyboardShiftState.java
index 3e1eaf44e..d5412791d 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardShiftState.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardShiftState.java
@@ -24,26 +24,38 @@ public class KeyboardShiftState {
private static final int NORMAL = 0;
private static final int MANUAL_SHIFTED = 1;
- private static final int SHIFT_LOCKED = 2;
+ private static final int MANUAL_SHIFTED_FROM_AUTO = 2;
private static final int AUTO_SHIFTED = 3;
- private static final int SHIFT_LOCK_SHIFTED = 4;
+ private static final int SHIFT_LOCKED = 4;
+ private static final int SHIFT_LOCK_SHIFTED = 5;
private int mState = NORMAL;
public boolean setShifted(boolean newShiftState) {
final int oldState = mState;
if (newShiftState) {
- if (oldState == NORMAL || oldState == AUTO_SHIFTED) {
+ switch (oldState) {
+ case NORMAL:
mState = MANUAL_SHIFTED;
- } else if (oldState == SHIFT_LOCKED) {
+ break;
+ case AUTO_SHIFTED:
+ mState = MANUAL_SHIFTED_FROM_AUTO;
+ break;
+ case SHIFT_LOCKED:
mState = SHIFT_LOCK_SHIFTED;
+ break;
}
} else {
- if (oldState == MANUAL_SHIFTED || oldState == AUTO_SHIFTED) {
+ switch (oldState) {
+ case MANUAL_SHIFTED:
+ case MANUAL_SHIFTED_FROM_AUTO:
+ case AUTO_SHIFTED:
mState = NORMAL;
- } else if (oldState == SHIFT_LOCK_SHIFTED) {
+ break;
+ case SHIFT_LOCK_SHIFTED:
mState = SHIFT_LOCKED;
- }
+ break;
+ }
}
if (DEBUG)
Log.d(TAG, "setShifted(" + newShiftState + "): " + toString(oldState) + " > " + this);
@@ -53,11 +65,21 @@ public class KeyboardShiftState {
public void setShiftLocked(boolean newShiftLockState) {
final int oldState = mState;
if (newShiftLockState) {
- if (oldState == NORMAL || oldState == MANUAL_SHIFTED || oldState == AUTO_SHIFTED)
+ switch (oldState) {
+ case NORMAL:
+ case MANUAL_SHIFTED:
+ case MANUAL_SHIFTED_FROM_AUTO:
+ case AUTO_SHIFTED:
mState = SHIFT_LOCKED;
+ break;
+ }
} else {
- if (oldState == SHIFT_LOCKED || oldState == SHIFT_LOCK_SHIFTED)
+ switch (oldState) {
+ case SHIFT_LOCKED:
+ case SHIFT_LOCK_SHIFTED:
mState = NORMAL;
+ break;
+ }
}
if (DEBUG)
Log.d(TAG, "setShiftLocked(" + newShiftLockState + "): " + toString(oldState)
@@ -84,7 +106,12 @@ public class KeyboardShiftState {
}
public boolean isManualTemporaryUpperCase() {
- return mState == MANUAL_SHIFTED || mState == SHIFT_LOCK_SHIFTED;
+ return mState == MANUAL_SHIFTED || mState == MANUAL_SHIFTED_FROM_AUTO
+ || mState == SHIFT_LOCK_SHIFTED;
+ }
+
+ public boolean isManualTemporaryUpperCaseFromAuto() {
+ return mState == MANUAL_SHIFTED_FROM_AUTO;
}
@Override
@@ -96,8 +123,9 @@ public class KeyboardShiftState {
switch (state) {
case NORMAL: return "NORMAL";
case MANUAL_SHIFTED: return "MANUAL_SHIFTED";
- case SHIFT_LOCKED: return "SHIFT_LOCKED";
+ case MANUAL_SHIFTED_FROM_AUTO: return "MANUAL_SHIFTED_FROM_AUTO";
case AUTO_SHIFTED: return "AUTO_SHIFTED";
+ case SHIFT_LOCKED: return "SHIFT_LOCKED";
case SHIFT_LOCK_SHIFTED: return "SHIFT_LOCK_SHIFTED";
default: return "UKNOWN";
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 331c8db6a..558de66a4 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -157,7 +157,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
boolean voiceButtonOnPrimary) {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
try {
+ if (mInputView == null) return;
+ final Keyboard oldKeyboard = mInputView.getKeyboard();
loadKeyboardInternal(mode, imeOptions, voiceKeyEnabled, voiceButtonOnPrimary, false);
+ final Keyboard newKeyboard = mInputView.getKeyboard();
+ if (newKeyboard.isAlphaKeyboard()) {
+ final boolean localeChanged = (oldKeyboard == null)
+ || !newKeyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
+ mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
+ }
} catch (RuntimeException e) {
Log.w(TAG, e);
LatinImeLogger.logOnException(mode + "," + imeOptions, e);
@@ -167,7 +175,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private void loadKeyboardInternal(int mode, int imeOptions, boolean voiceButtonEnabled,
boolean voiceButtonOnPrimary, boolean isSymbols) {
if (mInputView == null) return;
- mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
mMode = mode;
mImeOptions = imeOptions;
@@ -176,13 +183,16 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mIsSymbols = isSymbols;
// Update the settings key state because number of enabled IMEs could have been changed
mHasSettingsKey = getSettingsKeyMode(mPrefs, mInputMethodService);
- makeSymbolsKeyboardIds();
+ final KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
- KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
- LatinKeyboard keyboard = getKeyboard(id);
+ final Keyboard oldKeyboard = mInputView.getKeyboard();
+ if (oldKeyboard != null && oldKeyboard.mId.equals(id))
+ return;
+ makeSymbolsKeyboardIds();
mCurrentId = id;
- mInputView.setKeyboard(keyboard);
+ mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
+ mInputView.setKeyboard(getKeyboard(id));
}
private LatinKeyboard getKeyboard(KeyboardId id) {
@@ -210,6 +220,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
keyboard.onAutoCorrectionStateChanged(mIsAutoCorrectionActive);
keyboard.setShifted(false);
+ // If the cached keyboard had been switched to another keyboard while the language was
+ // displayed on its spacebar, it might have had arbitrary text fade factor. In such case,
+ // we should reset the text fade factor.
+ keyboard.setSpacebarTextFadeFactor(0.0f, null);
return keyboard;
}
@@ -313,6 +327,13 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return false;
}
+ private boolean isManualTemporaryUpperCaseFromAuto() {
+ LatinKeyboard latinKeyboard = getLatinKeyboard();
+ if (latinKeyboard != null)
+ return latinKeyboard.isManualTemporaryUpperCaseFromAuto();
+ return false;
+ }
+
private void setManualTemporaryUpperCase(boolean shifted) {
LatinKeyboard latinKeyboard = getLatinKeyboard();
if (latinKeyboard != null) {
@@ -468,6 +489,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
} else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()) {
// Shift has been pressed without chording while shifted state.
toggleShift();
+ } else if (isManualTemporaryUpperCaseFromAuto() && shiftKeyState.isPressing()) {
+ // Shift has been pressed without chording while manual temporary upper case
+ // transited from automatic temporary upper case.
+ toggleShift();
}
}
shiftKeyState.onRelease();
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index e7dd716fb..766fdf0e6 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -298,8 +298,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
- LayoutInflater inflate =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int previewLayout = 0;
int keyTextSize = 0;
@@ -365,7 +363,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
mPreviewPopup = new PopupWindow(context);
if (previewLayout != 0) {
- mPreviewText = (TextView) inflate.inflate(previewLayout, null);
+ mPreviewText = (TextView) LayoutInflater.from(context).inflate(previewLayout, null);
mPreviewTextSizeLarge = (int) res.getDimension(R.dimen.key_preview_text_size_large);
mPreviewPopup.setContentView(mPreviewText);
mPreviewPopup.setBackgroundDrawable(null);
@@ -912,9 +910,8 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
// We should re-draw popup preview when 1) we need to hide the preview, 2) we will show
// the space key preview and 3) pointer moves off the space key to other letter key, we
// should hide the preview of the previous key.
- @SuppressWarnings("unused")
final boolean hidePreviewOrShowSpaceKeyPreview = (tracker == null)
- || (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER
+ || (SubtypeSwitcher.getInstance().useSpacebarLanguageSwitcher()
&& SubtypeSwitcher.getInstance().needsToDisplayLanguage()
&& (tracker.isSpaceKey(keyIndex) || tracker.isSpaceKey(oldKeyIndex)));
// If key changed and preview is on or the key is space (language switch is enabled)
@@ -1081,9 +1078,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
private View inflateMiniKeyboardContainer(Key popupKey) {
int popupKeyboardResId = mKeyboard.getPopupKeyboardResId();
- LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- View container = inflater.inflate(mPopupLayout, null);
+ View container = LayoutInflater.from(getContext()).inflate(mPopupLayout, null);
if (container == null)
throw new NullPointerException();
@@ -1410,6 +1405,12 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
mBuffer = null;
mCanvas = null;
mMiniKeyboardCache.clear();
+ requestLayout();
+ }
+
+ public void purgeKeyboardAndClosing() {
+ mKeyboard = null;
+ closing();
}
@Override
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
index 77dde8d1b..888375b93 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
@@ -24,6 +24,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.PorterDuff;
@@ -47,7 +48,9 @@ public class LatinKeyboard extends Keyboard {
private final Drawable mSpaceAutoCorrectionIndicator;
private final Drawable mButtonArrowLeftIcon;
private final Drawable mButtonArrowRightIcon;
- private final int mSpaceBarTextShadowColor;
+ private final int mSpacebarTextColor;
+ private final int mSpacebarTextShadowColor;
+ private float mSpacebarTextFadeFactor = 0.0f;
private final int[] mSpaceKeyIndexArray;
private int mSpaceDragStartX;
private int mSpaceDragLastDiff;
@@ -80,11 +83,12 @@ public class LatinKeyboard extends Keyboard {
super(context, id.getXmlId(), id);
final Resources res = context.getResources();
mContext = context;
+ mSpacebarTextColor = res.getColor(R.color.latinkeyboard_bar_language_text);
if (id.mColorScheme == KeyboardView.COLOR_SCHEME_BLACK) {
- mSpaceBarTextShadowColor = res.getColor(
+ mSpacebarTextShadowColor = res.getColor(
R.color.latinkeyboard_bar_language_shadow_black);
} else { // default color scheme is KeyboardView.COLOR_SCHEME_WHITE
- mSpaceBarTextShadowColor = res.getColor(
+ mSpacebarTextShadowColor = res.getColor(
R.color.latinkeyboard_bar_language_shadow_white);
}
mSpaceAutoCorrectionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led);
@@ -96,25 +100,38 @@ public class LatinKeyboard extends Keyboard {
mSpaceKeyIndexArray = new int[] { indexOf(CODE_SPACE) };
}
+ public void setSpacebarTextFadeFactor(float fadeFactor, LatinKeyboardView view) {
+ mSpacebarTextFadeFactor = fadeFactor;
+ updateSpacebarForLocale(false);
+ if (view != null)
+ view.invalidateKey(mSpaceKey);
+ }
+
+ private static int getSpacebarTextColor(int color, float fadeFactor) {
+ final int newColor = Color.argb((int)(Color.alpha(color) * fadeFactor),
+ Color.red(color), Color.green(color), Color.blue(color));
+ return newColor;
+ }
+
/**
* @return a key which should be invalidated.
*/
public Key onAutoCorrectionStateChanged(boolean isAutoCorrection) {
- updateSpaceBarForLocale(isAutoCorrection);
+ updateSpacebarForLocale(isAutoCorrection);
return mSpaceKey;
}
- private void updateSpaceBarForLocale(boolean isAutoCorrection) {
+ private void updateSpacebarForLocale(boolean isAutoCorrection) {
final Resources res = mContext.getResources();
// If application locales are explicitly selected.
if (SubtypeSwitcher.getInstance().needsToDisplayLanguage()) {
mSpaceKey.setIcon(new BitmapDrawable(res,
- drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCorrection)));
+ drawSpacebar(OPACITY_FULLY_OPAQUE, isAutoCorrection)));
} else {
// sym_keyboard_space_led can be shared with Black and White symbol themes.
if (isAutoCorrection) {
mSpaceKey.setIcon(new BitmapDrawable(res,
- drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCorrection)));
+ drawSpacebar(OPACITY_FULLY_OPAQUE, isAutoCorrection)));
} else {
mSpaceKey.setIcon(mSpaceIcon);
}
@@ -128,8 +145,8 @@ public class LatinKeyboard extends Keyboard {
return bounds.width();
}
- // Layout local language name and left and right arrow on space bar.
- private static String layoutSpaceBar(Paint paint, Locale locale, Drawable lArrow,
+ // Layout local language name and left and right arrow on spacebar.
+ private static String layoutSpacebar(Paint paint, Locale locale, Drawable lArrow,
Drawable rArrow, int width, int height, float origTextSize,
boolean allowVariableTextSize) {
final float arrowWidth = lArrow.getIntrinsicWidth();
@@ -138,7 +155,7 @@ public class LatinKeyboard extends Keyboard {
final Rect bounds = new Rect();
// Estimate appropriate language name text size to fit in maxTextWidth.
- String language = SubtypeSwitcher.getDisplayLanguage(locale);
+ String language = SubtypeSwitcher.getFullDisplayName(locale, true);
int textWidth = getTextWidth(paint, language, origTextSize, bounds);
// Assuming text width and text size are proportional to each other.
float textSize = origTextSize * Math.min(maxTextWidth / textWidth, 1.0f);
@@ -171,8 +188,7 @@ public class LatinKeyboard extends Keyboard {
return language;
}
- @SuppressWarnings("unused")
- private Bitmap drawSpaceBar(int opacity, boolean isAutoCorrection) {
+ private Bitmap drawSpacebar(int opacity, boolean isAutoCorrection) {
final int width = mSpaceKey.mWidth;
final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : mSpaceKey.mHeight;
final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
@@ -202,21 +218,25 @@ public class LatinKeyboard extends Keyboard {
}
final boolean allowVariableTextSize = true;
- final String language = layoutSpaceBar(paint, subtypeSwitcher.getInputLocale(),
+ final String language = layoutSpacebar(paint, subtypeSwitcher.getInputLocale(),
mButtonArrowLeftIcon, mButtonArrowRightIcon, width, height,
getTextSizeFromTheme(textStyle, defaultTextSize),
allowVariableTextSize);
// Draw language text with shadow
- final float baseline = height * SPACEBAR_LANGUAGE_BASELINE;
+ // In case there is no space icon, we will place the language text at the center of
+ // spacebar.
final float descent = paint.descent();
- paint.setColor(mSpaceBarTextShadowColor);
+ final float textHeight = -paint.ascent() + descent;
+ final float baseline = (mSpaceIcon != null) ? height * SPACEBAR_LANGUAGE_BASELINE
+ : height / 2 + textHeight / 2;
+ paint.setColor(getSpacebarTextColor(mSpacebarTextShadowColor, mSpacebarTextFadeFactor));
canvas.drawText(language, width / 2, baseline - descent - 1, paint);
- paint.setColor(res.getColor(R.color.latinkeyboard_bar_language_text));
+ paint.setColor(getSpacebarTextColor(mSpacebarTextColor, mSpacebarTextFadeFactor));
canvas.drawText(language, width / 2, baseline - descent, paint);
// Put arrows that are already layed out on either side of the text
- if (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER
+ if (SubtypeSwitcher.getInstance().useSpacebarLanguageSwitcher()
&& subtypeSwitcher.getEnabledKeyboardLocaleCount() > 1) {
mButtonArrowLeftIcon.draw(canvas);
mButtonArrowRightIcon.draw(canvas);
@@ -291,7 +311,6 @@ public class LatinKeyboard extends Keyboard {
* switching input languages.
*/
@Override
- @SuppressWarnings("unused") // SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER is constant
public boolean isInside(Key key, int pointX, int pointY) {
int x = pointX;
int y = pointY;
@@ -302,7 +321,7 @@ public class LatinKeyboard extends Keyboard {
if (code == CODE_DELETE) x -= key.mWidth / 6;
} else if (code == CODE_SPACE) {
y += LatinKeyboard.sSpacebarVerticalCorrection;
- if (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER
+ if (SubtypeSwitcher.getInstance().useSpacebarLanguageSwitcher()
&& SubtypeSwitcher.getInstance().getEnabledKeyboardLocaleCount() > 1) {
if (mCurrentlyInSpace) {
int diff = x - mSpaceDragStartX;
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 51bfbf1f9..e9d5580e8 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -85,6 +85,14 @@ public class LatinKeyboardView extends KeyboardView {
}
}
+ public void setSpacebarTextFadeFactor(float fadeFactor, LatinKeyboard oldKeyboard) {
+ final LatinKeyboard currentKeyboard = getLatinKeyboard();
+ // We should not set text fade factor to the keyboard which does not display the language on
+ // its spacebar.
+ if (currentKeyboard != null && currentKeyboard == oldKeyboard)
+ currentKeyboard.setSpacebarTextFadeFactor(fadeFactor, this);
+ }
+
@Override
protected boolean onLongPress(Key key) {
int primaryCode = key.mCode;
@@ -197,10 +205,10 @@ public class LatinKeyboardView extends KeyboardView {
@Override
public boolean onTouchEvent(MotionEvent me) {
LatinKeyboard keyboard = getLatinKeyboard();
+ if (keyboard == null) return true;
// If there was a sudden jump, return without processing the actual motion event.
- if (handleSuddenJump(me))
- return true;
+ if (handleSuddenJump(me)) return true;
// Reset any bounding box controls in the keyboard
if (me.getAction() == MotionEvent.ACTION_DOWN) {
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java
index 458a9eed4..c150baadb 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java
@@ -71,7 +71,7 @@ public class MiniKeyboardBuilder {
for (CharSequence popupSpec : popupCharacters) {
final CharSequence label = PopupCharactersParser.getLabel(popupSpec.toString());
// If the label is single letter, minKeyWidth is enough to hold the label.
- if (label.length() > 1) {
+ if (label != null && label.length() > 1) {
if (paint == null) {
paint = new Paint();
paint.setAntiAlias(true);
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index af08742d3..b6035e15e 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -42,6 +42,7 @@ public class BinaryDictionary extends Dictionary {
private static final int TYPED_LETTER_MULTIPLIER = 2;
+ private static final BinaryDictionary sInstance = new BinaryDictionary();
private int mDicTypeId;
private int mNativeDict;
private long mDictLength;
@@ -59,16 +60,24 @@ public class BinaryDictionary extends Dictionary {
}
}
+ private BinaryDictionary() {
+ }
+
/**
- * Create a dictionary from a raw resource file
+ * Initialize a dictionary from a raw resource file
* @param context application context for reading resources
* @param resId the resource containing the raw binary dictionary
+ * @return initialized instance of BinaryDictionary
*/
- public BinaryDictionary(Context context, int resId, int dicTypeId) {
- if (resId != 0) {
- loadDictionary(context, resId);
+ public static BinaryDictionary initDictionary(Context context, int resId, int dicTypeId) {
+ synchronized (sInstance) {
+ sInstance.closeInternal();
+ if (resId != 0) {
+ sInstance.loadDictionary(context, resId);
+ sInstance.mDicTypeId = dicTypeId;
+ }
}
- mDicTypeId = dicTypeId;
+ return sInstance;
}
private native int openNative(String sourceDir, long dictOffset, long dictSize,
@@ -104,6 +113,8 @@ public class BinaryDictionary extends Dictionary {
@Override
public void getBigrams(final WordComposer codes, final CharSequence previousWord,
final WordCallback callback, int[] nextLettersFrequencies) {
+ if (mNativeDict == 0) return;
+
char[] chars = previousWord.toString().toCharArray();
Arrays.fill(mOutputChars_bigrams, (char) 0);
Arrays.fill(mFrequencies_bigrams, 0);
@@ -135,6 +146,8 @@ public class BinaryDictionary extends Dictionary {
@Override
public void getWords(final WordComposer codes, final WordCallback callback,
int[] nextLettersFrequencies) {
+ if (mNativeDict == 0) return;
+
final int codesSize = codes.size();
// Won't deal with really long words.
if (codesSize > MAX_WORD_LENGTH - 1) return;
@@ -179,6 +192,10 @@ public class BinaryDictionary extends Dictionary {
@Override
public synchronized void close() {
+ closeInternal();
+ }
+
+ private void closeInternal() {
if (mNativeDict != 0) {
closeNative(mNativeDict);
mNativeDict = 0;
@@ -188,7 +205,10 @@ public class BinaryDictionary extends Dictionary {
@Override
protected void finalize() throws Throwable {
- close();
- super.finalize();
+ try {
+ closeInternal();
+ } finally {
+ super.finalize();
+ }
}
}
diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java
index 30f4a59f9..d2d1f22dd 100644
--- a/java/src/com/android/inputmethod/latin/CandidateView.java
+++ b/java/src/com/android/inputmethod/latin/CandidateView.java
@@ -45,23 +45,22 @@ import android.widget.TextView;
import java.util.ArrayList;
public class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener {
- private LatinIME mService;
- private final ArrayList<View> mWords = new ArrayList<View>();
- private final TextView mPreviewText;
- private final PopupWindow mPreviewPopup;
-
+ private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
+ private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
private static final int MAX_SUGGESTIONS = 16;
+ private final ArrayList<View> mWords = new ArrayList<View>();
private final boolean mConfigCandidateHighlightFontColorEnabled;
+ private final CharacterStyle mInvertedForegroundColorSpan;
+ private final CharacterStyle mInvertedBackgroundColorSpan;
private final int mColorNormal;
private final int mColorRecommended;
private final int mColorOther;
- private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
- private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
- private final CharacterStyle mInvertedForegroundColorSpan;
- private final CharacterStyle mInvertedBackgroundColorSpan;
+ private final PopupWindow mPreviewPopup;
+ private final TextView mPreviewText;
+ private LatinIME mService;
private SuggestedWords mSuggestions = SuggestedWords.EMPTY;
private boolean mShowingAutoCorrectionInverted;
private boolean mShowingAddToDictionary;
@@ -186,9 +185,10 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
final TextView tv = (TextView)v.findViewById(R.id.candidate_word);
final TextView dv = (TextView)v.findViewById(R.id.candidate_debug_info);
tv.setTextColor(mColorNormal);
+ // TODO: Needs safety net?
if (suggestions.mHasMinimalSuggestion
- && ((i == 1 && !suggestions.mTypedWordValid) ||
- (i == 0 && suggestions.mTypedWordValid))) {
+ && ((i == 1 && !suggestions.mTypedWordValid)
+ || (i == 0 && suggestions.mTypedWordValid))) {
final CharacterStyle style;
if (mConfigCandidateHighlightFontColorEnabled) {
style = BOLD_SPAN;
@@ -329,7 +329,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
mService.pickSuggestionManually(index, word);
}
}
-
+
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
diff --git a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java
index faee38eda..a9f2c2c22 100644
--- a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java
+++ b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java
@@ -107,7 +107,7 @@ public class InputLanguageSelection extends PreferenceActivity {
res.updateConfiguration(conf, res.getDisplayMetrics());
int mainDicResId = LatinIME.getMainDictionaryResourceId(res);
- BinaryDictionary bd = new BinaryDictionary(this, mainDicResId, Suggest.DIC_MAIN);
+ BinaryDictionary bd = BinaryDictionary.initDictionary(this, mainDicResId, Suggest.DIC_MAIN);
// Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of
// 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words.
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index ad7e4708a..b6042c769 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -22,6 +22,7 @@ import com.android.inputmethod.keyboard.KeyboardActionListener;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.KeyboardView;
+import com.android.inputmethod.keyboard.LatinKeyboard;
import com.android.inputmethod.keyboard.LatinKeyboardView;
import com.android.inputmethod.latin.Utils.RingCharBuffer;
import com.android.inputmethod.voice.VoiceIMEConnector;
@@ -132,14 +133,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private Resources mResources;
private SharedPreferences mPrefs;
+ // These variables are initialized according to the {@link EditorInfo#inputType}.
+ private boolean mAutoSpace;
+ private boolean mInputTypeNoAutoCorrect;
+ private boolean mIsSettingsSuggestionStripOn;
+ private boolean mApplicationSpecifiedCompletionOn;
+
private final StringBuilder mComposing = new StringBuilder();
private WordComposer mWord = new WordComposer();
private CharSequence mBestWord;
private boolean mHasValidSuggestions;
- private boolean mIsSettingsSuggestionStripOn;
- private boolean mApplicationSpecifiedCompletionOn;
private boolean mHasDictionary;
- private boolean mAutoSpace;
private boolean mJustAddedAutoSpace;
private boolean mAutoCorrectEnabled;
private boolean mReCorrectionEnabled;
@@ -151,6 +155,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private boolean mAutoCap;
private boolean mQuickFixes;
private boolean mConfigSwipeDownDismissKeyboardEnabled;
+ private int mConfigDelayBeforeFadeoutLanguageOnSpacebar;
+ private int mConfigDurationOfFadeoutLanguageOnSpacebar;
+ private float mConfigFinalFadeoutFactorOfLanguageOnSpacebar;
private int mCorrectionMode;
private int mCommittedLength;
@@ -160,9 +167,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private int mLastSelectionEnd;
private SuggestedWords mSuggestPuncList;
- // Input type is such that we should not auto-correct
- private boolean mInputTypeNoAutoCorrect;
-
// Indicates whether the suggestion strip is to be on in landscape
private boolean mJustAccepted;
private boolean mJustReverted;
@@ -241,9 +245,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
private static final int MSG_UPDATE_SHIFT_STATE = 2;
private static final int MSG_VOICE_RESULTS = 3;
+ private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
+ private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
@Override
public void handleMessage(Message msg) {
+ final KeyboardSwitcher switcher = mKeyboardSwitcher;
+ final LatinKeyboardView inputView = switcher.getInputView();
switch (msg.what) {
case MSG_UPDATE_SUGGESTIONS:
updateSuggestions();
@@ -252,12 +260,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
setOldSuggestions();
break;
case MSG_UPDATE_SHIFT_STATE:
- mKeyboardSwitcher.updateShiftState();
+ switcher.updateShiftState();
break;
case MSG_VOICE_RESULTS:
mVoiceConnector.handleVoiceResults(preferCapitalization()
- || (mKeyboardSwitcher.isAlphabetMode()
- && mKeyboardSwitcher.isShiftedOrShiftLocked()));
+ || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
+ break;
+ case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
+ if (inputView != null)
+ inputView.setSpacebarTextFadeFactor(
+ (1.0f + mConfigFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
+ (LatinKeyboard)msg.obj);
+ sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
+ mConfigDurationOfFadeoutLanguageOnSpacebar);
+ break;
+ case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
+ if (inputView != null)
+ inputView.setSpacebarTextFadeFactor(
+ mConfigFinalFadeoutFactorOfLanguageOnSpacebar, (LatinKeyboard)msg.obj);
break;
}
}
@@ -297,6 +317,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void updateVoiceResults() {
sendMessage(obtainMessage(MSG_VOICE_RESULTS));
}
+
+ public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
+ removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
+ removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
+ final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
+ if (inputView != null) {
+ final LatinKeyboard keyboard = inputView.getLatinKeyboard();
+ // The language is never displayed when the delay is zero.
+ if (mConfigDelayBeforeFadeoutLanguageOnSpacebar != 0)
+ inputView.setSpacebarTextFadeFactor(localeChanged ? 1.0f
+ : mConfigFinalFadeoutFactorOfLanguageOnSpacebar, keyboard);
+ // The language is always displayed when the delay is negative.
+ if (localeChanged && mConfigDelayBeforeFadeoutLanguageOnSpacebar > 0) {
+ sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
+ mConfigDelayBeforeFadeoutLanguageOnSpacebar);
+ }
+ }
+ }
}
@Override
@@ -315,10 +353,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final Resources res = getResources();
mResources = res;
- mReCorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
- res.getBoolean(R.bool.default_recorrection_enabled));
+
+ // If the option should not be shown, do not read the recorrection preference
+ // but always use the default setting defined in the resources.
+ if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) {
+ mReCorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
+ res.getBoolean(R.bool.default_recorrection_enabled));
+ } else {
+ mReCorrectionEnabled = res.getBoolean(R.bool.default_recorrection_enabled);
+ }
+
mConfigSwipeDownDismissKeyboardEnabled = res.getBoolean(
R.bool.config_swipe_down_dismiss_keyboard_enabled);
+ mConfigDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger(
+ R.integer.config_delay_before_fadeout_language_on_spacebar);
+ mConfigDurationOfFadeoutLanguageOnSpacebar = res.getInteger(
+ R.integer.config_duration_of_fadeout_language_on_spacebar);
+ mConfigFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger(
+ R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f;
Utils.GCUtils.getInstance().reset();
boolean tryGC = true;
@@ -360,7 +412,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mSuggest.close();
}
final SharedPreferences prefs = mPrefs;
- mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true);
+ mQuickFixes = isQuickFixesEnabled(prefs);
final Resources res = mResources;
int mainDicResId = getMainDictionaryResourceId(res);
@@ -402,27 +454,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onConfigurationChanged(Configuration conf) {
mSubtypeSwitcher.onConfigurationChanged(conf);
- if (mSubtypeSwitcher.isKeyboardMode())
- onKeyboardLanguageChanged();
- updateAutoTextEnabled();
-
// 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;
- final int mode = mKeyboardSwitcher.getKeyboardMode();
- final EditorInfo attribute = getCurrentInputEditorInfo();
- final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
- mKeyboardSwitcher.loadKeyboard(mode, imeOptions,
- mVoiceConnector.isVoiceButtonEnabled(),
- mVoiceConnector.isVoiceButtonOnPrimary());
}
mConfigurationChanging = true;
super.onConfigurationChanged(conf);
- mVoiceConnector.onConfigurationChanged(mConfigurationChanging);
+ mVoiceConnector.onConfigurationChanged(conf);
mConfigurationChanging = false;
}
@@ -473,24 +515,62 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (mRefreshKeyboardRequired) {
mRefreshKeyboardRequired = false;
- onKeyboardLanguageChanged();
+ onRefreshKeyboard();
}
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.
- int variation = attribute.inputType & InputType.TYPE_MASK_VARIATION;
- mVoiceConnector.resetVoiceStates(isPasswordVariation(variation));
+ // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
+ // know now whether this is a password text field, because we need to know now whether we
+ // want to enable the voice button.
+ mVoiceConnector.resetVoiceStates(isPasswordVariation(
+ attribute.inputType & InputType.TYPE_MASK_VARIATION));
+
+ final int mode = initializeInputAttributesAndGetMode(attribute.inputType);
+
+ inputView.closing();
+ mEnteredText = null;
+ mComposing.setLength(0);
+ mHasValidSuggestions = false;
+ mDeleteCount = 0;
+ mJustAddedAutoSpace = false;
+
+ loadSettings(attribute);
+ if (mSubtypeSwitcher.isKeyboardMode()) {
+ switcher.loadKeyboard(mode, attribute.imeOptions,
+ mVoiceConnector.isVoiceButtonEnabled(),
+ mVoiceConnector.isVoiceButtonOnPrimary());
+ switcher.updateShiftState();
+ }
+
+ setCandidatesViewShownInternal(isCandidateStripVisible(),
+ false /* needsInputViewShown */ );
+ // Delay updating suggestions because keyboard input view may not be shown at this point.
+ mHandler.postUpdateSuggestions();
+
+ updateCorrectionMode();
+
+ inputView.setPreviewEnabled(mPopupOn);
+ inputView.setProximityCorrectionEnabled(true);
+ // If we just entered a text field, maybe it has some old text that requires correction
+ checkReCorrectionOnStart();
+ inputView.setForeground(true);
+
+ mVoiceConnector.onStartInputView(inputView.getWindowToken());
+
+ if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
+ }
+
+ private int initializeInputAttributesAndGetMode(int inputType) {
+ final int variation = inputType & InputType.TYPE_MASK_VARIATION;
+ mAutoSpace = false;
mInputTypeNoAutoCorrect = false;
mIsSettingsSuggestionStripOn = false;
mApplicationSpecifiedCompletionOn = false;
mApplicationSpecifiedCompletions = null;
- mEnteredText = null;
final int mode;
- switch (attribute.inputType & InputType.TYPE_MASK_CLASS) {
+ switch (inputType & InputType.TYPE_MASK_CLASS) {
case InputType.TYPE_CLASS_NUMBER:
case InputType.TYPE_CLASS_DATETIME:
mode = KeyboardId.MODE_NUMBER;
@@ -525,7 +605,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mode = KeyboardId.MODE_WEB;
// 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 & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
+ if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
mInputTypeNoAutoCorrect = true;
}
} else {
@@ -533,16 +613,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
// If NO_SUGGESTIONS is set, don't do prediction.
- if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
+ if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
mIsSettingsSuggestionStripOn = false;
mInputTypeNoAutoCorrect = true;
}
// If it's not multiline and the autoCorrect flag is not set, then don't correct
- if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
- (attribute.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
+ if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
+ (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
mInputTypeNoAutoCorrect = true;
}
- if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
+ if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
mIsSettingsSuggestionStripOn = false;
mApplicationSpecifiedCompletionOn = isFullscreenMode();
}
@@ -551,40 +631,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mode = KeyboardId.MODE_TEXT;
break;
}
- inputView.closing();
- mComposing.setLength(0);
- mHasValidSuggestions = false;
- mDeleteCount = 0;
- mJustAddedAutoSpace = false;
-
- loadSettings(attribute);
- if (mSubtypeSwitcher.isKeyboardMode()) {
- switcher.loadKeyboard(mode, attribute.imeOptions,
- mVoiceConnector.isVoiceButtonEnabled(),
- mVoiceConnector.isVoiceButtonOnPrimary());
- switcher.updateShiftState();
- }
-
- setCandidatesViewShownInternal(isCandidateStripVisible(),
- false /* needsInputViewShown */ );
- // Delay updating suggestions because keyboard input view may not be shown at this point.
- mHandler.postUpdateSuggestions();
-
- // If the dictionary is not big enough, don't auto correct
- mHasDictionary = mSuggest.hasMainDictionary();
-
- updateCorrectionMode();
-
- inputView.setPreviewEnabled(mPopupOn);
- inputView.setProximityCorrectionEnabled(true);
- mIsSettingsSuggestionStripOn &= (mCorrectionMode > 0 || isShowingSuggestionsStrip());
- // If we just entered a text field, maybe it has some old text that requires correction
- checkReCorrectionOnStart();
- inputView.setForeground(true);
-
- mVoiceConnector.onStartInputView(mKeyboardSwitcher.getInputView().getWindowToken());
-
- if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
+ return mode;
}
private void checkReCorrectionOnStart() {
@@ -1106,14 +1153,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void handleBackspace() {
if (mVoiceConnector.logAndRevertVoiceInput()) return;
- boolean deleteChar = false;
- InputConnection ic = getCurrentInputConnection();
- if (ic == null) return;
+ final InputConnection ic = getCurrentInputConnection();
+ if (ic == null) return;
ic.beginBatchEdit();
mVoiceConnector.handleBackspace();
+ boolean deleteChar = false;
if (mHasValidSuggestions) {
final int length = mComposing.length();
if (length > 0) {
@@ -1131,12 +1178,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
deleteChar = true;
}
mHandler.postUpdateShiftKeyState();
+
TextEntryState.backspace();
if (TextEntryState.getState() == TextEntryState.State.UNDO_COMMIT) {
revertLastWord(deleteChar);
ic.endBatchEdit();
return;
- } else if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
+ }
+
+ if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
ic.deleteSurroundingText(mEnteredText.length(), 0);
} else if (deleteChar) {
if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
@@ -1355,7 +1405,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private boolean isSuggestionsRequested() {
- return mIsSettingsSuggestionStripOn;
+ return mIsSettingsSuggestionStripOn
+ && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
}
private boolean isShowingPunctuationList() {
@@ -1491,7 +1542,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
setSuggestions(suggestedWords);
if (suggestedWords.size() > 0) {
- if (suggestedWords.hasAutoCorrectionWord()) {
+ if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords)) {
+ mBestWord = typedWord;
+ } else if (suggestedWords.hasAutoCorrectionWord()) {
mBestWord = suggestedWords.getWord(1);
} else {
mBestWord = typedWord;
@@ -1773,18 +1826,31 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final int length = mComposing.length();
if (!mHasValidSuggestions && length > 0) {
final InputConnection ic = getCurrentInputConnection();
- mHasValidSuggestions = true;
mJustReverted = true;
+ final CharSequence punctuation = 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))) {
+ final CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
+ if (!TextUtils.isEmpty(toTheLeft) && isWordSeparator(toTheLeft.charAt(0))) {
toDelete--;
}
ic.deleteSurroundingText(toDelete, 0);
- ic.setComposingText(mComposing, 1);
- TextEntryState.backspace();
+ // Re-insert punctuation only when the deleted character was word separator and the
+ // composing text wasn't equal to the auto-corrected text.
+ if (deleteChar
+ && !TextUtils.isEmpty(punctuation) && isWordSeparator(punctuation.charAt(0))
+ && !TextUtils.equals(mComposing, toTheLeft)) {
+ ic.commitText(mComposing, 1);
+ TextEntryState.acceptedTyped(mComposing);
+ ic.commitText(punctuation, 1);
+ TextEntryState.typedCharacter(punctuation.charAt(0), true);
+ // Clear composing text
+ mComposing.setLength(0);
+ } else {
+ mHasValidSuggestions = true;
+ ic.setComposingText(mComposing, 1);
+ TextEntryState.backspace();
+ }
mHandler.postUpdateSuggestions();
} else {
sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
@@ -1814,21 +1880,22 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return mWord.isFirstCharCapitalized();
}
- // Notify that Language has been changed and toggleLanguage will update KeyboaredID according
- // to new Language.
- public void onKeyboardLanguageChanged() {
+ // Notify that language or mode have been changed and toggleLanguage will update KeyboaredID
+ // according to new language or mode.
+ public void onRefreshKeyboard() {
toggleLanguage(true, true);
}
// "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
private void toggleLanguage(boolean reset, boolean next) {
- if (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
mSubtypeSwitcher.toggleLanguage(reset, next);
}
// Reload keyboard because the current language has been changed.
KeyboardSwitcher switcher = mKeyboardSwitcher;
- final int mode = switcher.getKeyboardMode();
final EditorInfo attribute = getCurrentInputEditorInfo();
+ final int mode = initializeInputAttributesAndGetMode((attribute != null)
+ ? attribute.inputType : 0);
final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(),
mVoiceConnector.isVoiceButtonOnPrimary());
@@ -2016,7 +2083,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mPopupOn = prefs.getBoolean(Settings.PREF_POPUP_ON,
mResources.getBoolean(R.bool.config_default_popup_preview));
mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
- mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true);
+ mQuickFixes = isQuickFixesEnabled(prefs);
mAutoCorrectEnabled = isAutoCorrectEnabled(prefs);
mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(prefs);
@@ -2065,6 +2132,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mSuggest.setAutoCorrectionThreshold(autoCorrectionThreshold);
}
+ private boolean isQuickFixesEnabled(SharedPreferences sp) {
+ final boolean showQuickFixesOption = mResources.getBoolean(
+ R.bool.config_enable_quick_fixes_option);
+ if (!showQuickFixesOption) {
+ return isAutoCorrectEnabled(sp);
+ }
+ return sp.getBoolean(Settings.PREF_QUICK_FIXES, mResources.getBoolean(
+ R.bool.config_default_quick_fixes));
+ }
+
private boolean isAutoCorrectEnabled(SharedPreferences sp) {
final String currentAutoCorrectionSetting = sp.getString(
Settings.PREF_AUTO_CORRECTION_THRESHOLD,
@@ -2075,8 +2152,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private boolean isBigramSuggestionEnabled(SharedPreferences sp) {
- // TODO: Define default value instead of 'true'.
- return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, true);
+ final boolean showBigramSuggestionsOption = mResources.getBoolean(
+ R.bool.config_enable_bigram_suggestions_option);
+ if (!showBigramSuggestionsOption) {
+ return isAutoCorrectEnabled(sp);
+ }
+ return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, mResources.getBoolean(
+ R.bool.config_default_bigram_suggestions));
}
private void initSuggestPuncList() {
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index d3fb23baf..c78e6dd07 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -1,6 +1,6 @@
/*
* 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
@@ -48,6 +48,7 @@ public class Settings extends PreferenceActivity
DialogInterface.OnDismissListener, OnPreferenceClickListener {
private static final String TAG = "Settings";
+ public static final String PREF_GENERAL_SETTINGS_KEY = "general_settings";
public static final String PREF_VIBRATE_ON = "vibrate_on";
public static final String PREF_SOUND_ON = "sound_on";
public static final String PREF_POPUP_ON = "popup_on";
@@ -65,6 +66,8 @@ public class Settings extends PreferenceActivity
public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold";
public static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion";
+ public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
+
// Dialog ids
private static final int VOICE_INPUT_CONFIRM_DIALOG = 0;
@@ -111,30 +114,64 @@ public class Settings extends PreferenceActivity
mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTIONS);
ensureConsistencyOfAutoCorrectionSettings();
+ final PreferenceGroup generalSettings =
+ (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS_KEY);
+ final PreferenceGroup textCorrectionGroup =
+ (PreferenceGroup) findPreference(PREF_PREDICTION_SETTINGS_KEY);
+
final boolean showSettingsKeyOption = getResources().getBoolean(
R.bool.config_enable_show_settings_key_option);
if (!showSettingsKeyOption) {
- getPreferenceScreen().removePreference(mSettingsKeyPreference);
+ generalSettings.removePreference(mSettingsKeyPreference);
}
final boolean showVoiceKeyOption = getResources().getBoolean(
R.bool.config_enable_show_voice_key_option);
if (!showVoiceKeyOption) {
- getPreferenceScreen().removePreference(mVoicePreference);
+ generalSettings.removePreference(mVoicePreference);
}
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
if (vibrator == null
// @@@ || !vibrator.hasVibrator()
) {
- getPreferenceScreen().removePreference(
- getPreferenceScreen().findPreference(PREF_VIBRATE_ON));
+ generalSettings.removePreference(findPreference(PREF_VIBRATE_ON));
}
final boolean showSubtypeSettings = getResources().getBoolean(
R.bool.config_enable_show_subtype_settings);
if (!showSubtypeSettings) {
- getPreferenceScreen().removePreference(findPreference(PREF_SUBTYPES));
+ generalSettings.removePreference(findPreference(PREF_SUBTYPES));
+ }
+
+ final boolean showPopupOption = getResources().getBoolean(
+ R.bool.config_enable_show_popup_on_keypress_option);
+ if (!showPopupOption) {
+ generalSettings.removePreference(findPreference(PREF_POPUP_ON));
+ }
+
+ final boolean showRecorrectionOption = getResources().getBoolean(
+ R.bool.config_enable_show_recorrection_option);
+ if (!showRecorrectionOption) {
+ generalSettings.removePreference(findPreference(PREF_RECORRECTION_ENABLED));
+ }
+
+ final boolean showQuickFixesOption = getResources().getBoolean(
+ R.bool.config_enable_quick_fixes_option);
+ if (!showQuickFixesOption) {
+ textCorrectionGroup.removePreference(findPreference(PREF_QUICK_FIXES));
+ }
+
+ final boolean showBigramSuggestionsOption = getResources().getBoolean(
+ R.bool.config_enable_bigram_suggestions_option);
+ if (!showBigramSuggestionsOption) {
+ textCorrectionGroup.removePreference(findPreference(PREF_BIGRAM_SUGGESTIONS));
+ }
+
+ final boolean showUsabilityModeStudyOption = getResources().getBoolean(
+ R.bool.config_enable_usability_study_mode_option);
+ if (!showUsabilityModeStudyOption) {
+ getPreferenceScreen().removePreference(findPreference(PREF_USABILITY_STUDY_MODE));
}
}
@@ -184,7 +221,7 @@ public class Settings extends PreferenceActivity
if (pref == mInputLanguageSelection) {
final String action;
if (android.os.Build.VERSION.SDK_INT
- >= /* android.os.Build.VERSION_CODES.HONEYCOMB */ 10) {
+ >= /* android.os.Build.VERSION_CODES.HONEYCOMB */ 11) {
action = "android.settings.INPUT_METHOD_AND_SUBTYPE_ENABLER";
} else {
action = "com.android.inputmethod.latin.INPUT_LANGUAGE_SELECTION";
diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java
new file mode 100644
index 000000000..917521c40
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.Context;
+import android.content.res.Resources;
+
+import java.util.Locale;
+
+public class SubtypeLocale {
+ private static String[] sExceptionKeys;
+ private static String[] sExceptionValues;
+
+ private SubtypeLocale() {
+ // Intentional empty constructor for utility class.
+ }
+
+ public static void init(Context context) {
+ final Resources res = context.getResources();
+ sExceptionKeys = res.getStringArray(R.array.subtype_locale_exception_keys);
+ sExceptionValues = res.getStringArray(R.array.subtype_locale_exception_values);
+ }
+
+ public static String getFullDisplayName(Locale locale) {
+ String localeCode = locale.toString();
+ for (int index = 0; index < sExceptionKeys.length; index++) {
+ if (sExceptionKeys[index].equals(localeCode))
+ return sExceptionValues[index];
+ }
+ return locale.getDisplayName(locale);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index cb676fa00..6666c8e15 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -41,11 +41,6 @@ import java.util.Locale;
import java.util.Map;
public class SubtypeSwitcher {
- // TODO: This should be configurable by resource
- // This flag indicates if we support language switching by swipe on space bar.
- // We may or may not draw the current language on space bar regardless of this flag.
- // @@@
- public static final boolean USE_SPACEBAR_LANGUAGE_SWITCHER = true;
private static final boolean DBG = false;
private static final String TAG = "SubtypeSwitcher";
@@ -64,6 +59,8 @@ public class SubtypeSwitcher {
new ArrayList<InputMethodSubtype>();
private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>();
+ private boolean mConfigUseSpacebarLanguageSwitcher;
+
/*-----------------------------------------------------------*/
// Variants which should be changed only by reload functions.
private boolean mNeedsToDisplayLanguage;
@@ -85,11 +82,9 @@ public class SubtypeSwitcher {
public static void init(LatinIME service, SharedPreferences prefs) {
sInstance.mPrefs = prefs;
sInstance.resetParams(service);
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
- sInstance.initLanguageSwitcher(service);
- }
-
sInstance.updateAllParameters();
+
+ SubtypeLocale.init(service);
}
private SubtypeSwitcher() {
@@ -110,6 +105,10 @@ public class SubtypeSwitcher {
mAllEnabledSubtypesOfCurrentInputMethod = null;
// TODO: Voice input should be created here
mVoiceInput = null;
+ mConfigUseSpacebarLanguageSwitcher = mResources.getBoolean(
+ R.bool.config_use_spacebar_language_switcher);
+ if (mConfigUseSpacebarLanguageSwitcher)
+ initLanguageSwitcher(service);
}
// Update all parameters stored in SubtypeSwitcher.
@@ -123,8 +122,8 @@ public class SubtypeSwitcher {
// Update parameters which are changed outside LatinIME. This parameters affect UI so they
// should be updated every time onStartInputview.
public void updateParametersOnStartInputView() {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
- updateForSpaceBarLanguageSwitch();
+ if (mConfigUseSpacebarLanguageSwitcher) {
+ updateForSpacebarLanguageSwitch();
} else {
updateEnabledSubtypes();
}
@@ -135,7 +134,7 @@ public class SubtypeSwitcher {
private void updateEnabledSubtypes() {
boolean foundCurrentSubtypeBecameDisabled = true;
// @@@ mAllEnabledSubtypesOfCurrentInputMethod = mImm.getEnabledInputMethodSubtypeList(
- //null, false);
+ // null, true);
mEnabledLanguagesOfCurrentInputMethod.clear();
mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
for (InputMethodSubtype ims: mAllEnabledSubtypesOfCurrentInputMethod) {
@@ -156,6 +155,7 @@ public class SubtypeSwitcher {
&& mIsSystemLanguageSameAsInputLanguage);
if (foundCurrentSubtypeBecameDisabled) {
if (DBG) {
+ Log.w(TAG, "Current subtype: " + mInputLocaleStr + ", " + mMode);
Log.w(TAG, "Last subtype was disabled. Update to the current one.");
}
// @@@ updateSubtype(mImm.getCurrentInputMethodSubtype());
@@ -189,7 +189,7 @@ public class SubtypeSwitcher {
// fallback to the default locale and mode.
Log.w(TAG, "Couldn't get the current subtype.");
newLocale = "en_US";
- newMode =KEYBOARD_MODE;
+ newMode = KEYBOARD_MODE;
} else {
newLocale = newSubtype.getLocale();
newMode = newSubtype.getMode();
@@ -219,8 +219,8 @@ public class SubtypeSwitcher {
mVoiceInput.cancel();
}
}
- if (languageChanged) {
- mService.onKeyboardLanguageChanged();
+ if (modeChanged || languageChanged) {
+ mService.onRefreshKeyboard();
}
} else if (isVoiceMode()) {
// If needsToShowWarningDialog is true, voice input need to show warning before
@@ -312,19 +312,23 @@ public class SubtypeSwitcher {
//////////////////////////////////
public int getEnabledKeyboardLocaleCount() {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getLocaleCount();
} else {
return mEnabledKeyboardSubtypesOfCurrentInputMethod.size();
}
}
+ public boolean useSpacebarLanguageSwitcher() {
+ return mConfigUseSpacebarLanguageSwitcher;
+ }
+
public boolean needsToDisplayLanguage() {
return mNeedsToDisplayLanguage;
}
public Locale getInputLocale() {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getInputLocale();
} else {
return mInputLocale;
@@ -332,7 +336,7 @@ public class SubtypeSwitcher {
}
public String getInputLocaleStr() {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mConfigUseSpacebarLanguageSwitcher) {
String inputLanguage = null;
inputLanguage = mLanguageSwitcher.getInputLanguage();
// Should return system locale if there is no Language available.
@@ -346,7 +350,7 @@ public class SubtypeSwitcher {
}
public String[] getEnabledLanguages() {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getEnabledLanguages();
} else {
return mEnabledLanguagesOfCurrentInputMethod.toArray(
@@ -355,7 +359,7 @@ public class SubtypeSwitcher {
}
public Locale getSystemLocale() {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getSystemLocale();
} else {
return mSystemLocale;
@@ -363,7 +367,7 @@ public class SubtypeSwitcher {
}
public boolean isSystemLanguageSameAsInputLanguage() {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mConfigUseSpacebarLanguageSwitcher) {
return getSystemLocale().getLanguage().equalsIgnoreCase(
getInputLocaleStr().substring(0, 2));
} else {
@@ -375,7 +379,7 @@ public class SubtypeSwitcher {
final Locale systemLocale = conf.locale;
// If system configuration was changed, update all parameters.
if (!TextUtils.equals(systemLocale.toString(), mSystemLocale.toString())) {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mConfigUseSpacebarLanguageSwitcher) {
// If the system locale changes and is different from the saved
// locale (mSystemLocale), then reload the input locale list from the
// latin ime settings (shared prefs) and reset the input locale
@@ -389,7 +393,7 @@ public class SubtypeSwitcher {
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mConfigUseSpacebarLanguageSwitcher) {
if (Settings.PREF_SELECTED_LANGUAGES.equals(key)) {
mLanguageSwitcher.loadLocales(sharedPreferences);
}
@@ -439,18 +443,18 @@ public class SubtypeSwitcher {
private void triggerVoiceIME() {
if (!mService.isInputViewShown()) return;
VoiceIMEConnector.getInstance().startListening(false,
- KeyboardSwitcher.getInstance().getInputView().getWindowToken(), false);
+ KeyboardSwitcher.getInstance().getInputView().getWindowToken());
}
//////////////////////////////////////
- // SpaceBar Language Switch support //
+ // Spacebar Language Switch support //
//////////////////////////////////////
private LanguageSwitcher mLanguageSwitcher;
public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) {
if (returnsNameInThisLocale) {
- return toTitleCase(locale.getDisplayName(locale));
+ return toTitleCase(SubtypeLocale.getFullDisplayName(locale));
} else {
return toTitleCase(locale.getDisplayName());
}
@@ -471,7 +475,7 @@ public class SubtypeSwitcher {
return Character.toUpperCase(s.charAt(0)) + s.substring(1);
}
- private void updateForSpaceBarLanguageSwitch() {
+ private void updateForSpacebarLanguageSwitch() {
// We need to update mNeedsToDisplayLanguage in onStartInputView because
// getEnabledKeyboardLocaleCount could have been changed.
mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1
@@ -484,7 +488,7 @@ public class SubtypeSwitcher {
}
public String getNextInputLanguageName() {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mConfigUseSpacebarLanguageSwitcher) {
return getDisplayLanguage(mLanguageSwitcher.getNextInputLocale());
} else {
return "";
@@ -492,7 +496,7 @@ public class SubtypeSwitcher {
}
public String getPreviousInputLanguageName() {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mConfigUseSpacebarLanguageSwitcher) {
return getDisplayLanguage(mLanguageSwitcher.getPrevInputLocale());
} else {
return "";
@@ -529,13 +533,13 @@ public class SubtypeSwitcher {
}
public void loadSettings() {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mConfigUseSpacebarLanguageSwitcher) {
mLanguageSwitcher.loadLocales(mPrefs);
}
}
public void toggleLanguage(boolean reset, boolean next) {
- if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+ if (mConfigUseSpacebarLanguageSwitcher) {
if (reset) {
mLanguageSwitcher.reset();
} else {
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 9ea9c2f3e..24c73e8ea 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -31,7 +31,7 @@ import java.util.Arrays;
*/
public class Suggest implements Dictionary.WordCallback {
- public static final String TAG = "Suggest";
+ public static final String TAG = Suggest.class.getSimpleName();
public static final int APPROX_MAX_WORD_LENGTH = 32;
@@ -64,6 +64,8 @@ public class Suggest implements Dictionary.WordCallback {
static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000;
+ private static boolean DBG = LatinImeLogger.sDBG;
+
private BinaryDictionary mMainDict;
private Dictionary mUserDictionary;
@@ -93,7 +95,7 @@ public class Suggest implements Dictionary.WordCallback {
private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>();
private ArrayList<CharSequence> mStringPool = new ArrayList<CharSequence>();
- private boolean mHaveCorrection;
+ private boolean mHaveAutoCorrection;
private String mLowerOriginalWord;
// TODO: Remove these member variables by passing more context to addWord() callback method
@@ -103,7 +105,7 @@ public class Suggest implements Dictionary.WordCallback {
private int mCorrectionMode = CORRECTION_BASIC;
public Suggest(Context context, int dictionaryResId) {
- mMainDict = new BinaryDictionary(context, dictionaryResId, DIC_MAIN);
+ mMainDict = BinaryDictionary.initDictionary(context, dictionaryResId, DIC_MAIN);
initPool();
}
@@ -127,7 +129,7 @@ public class Suggest implements Dictionary.WordCallback {
}
public boolean hasMainDictionary() {
- return mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD;
+ return mMainDict != null && mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD;
}
public int getApproxMaxWordLength() {
@@ -198,7 +200,7 @@ public class Suggest implements Dictionary.WordCallback {
public SuggestedWords.Builder getSuggestedWordBuilder(View view, WordComposer wordComposer,
CharSequence prevWordForBigram) {
LatinImeLogger.onStartSuggestion(prevWordForBigram);
- mHaveCorrection = false;
+ mHaveAutoCorrection = false;
mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized();
mIsAllUpperCase = wordComposer.isAllUpperCase();
collectGarbage(mSuggestions, mPrefMaxSuggestions);
@@ -273,10 +275,13 @@ public class Suggest implements Dictionary.WordCallback {
if (mSuggestions.size() > 0 && isValidWord(typedWord)
&& (mCorrectionMode == CORRECTION_FULL
|| mCorrectionMode == CORRECTION_FULL_BIGRAM)) {
- mHaveCorrection = true;
+ if (DBG) {
+ Log.d(TAG, "Auto corrected by CORRECTION_FULL.");
+ }
+ mHaveAutoCorrection = true;
}
}
- mMainDict.getWords(wordComposer, this, mNextLettersFrequencies);
+ if (mMainDict != null) mMainDict.getWords(wordComposer, this, mNextLettersFrequencies);
if ((mCorrectionMode == CORRECTION_FULL || mCorrectionMode == CORRECTION_FULL_BIGRAM)
&& mSuggestions.size() > 0 && mPriorities.length > 0) {
// TODO: when the normalized score of the first suggestion is nearly equals to
@@ -289,7 +294,10 @@ public class Suggest implements Dictionary.WordCallback {
+ "(" + mAutoCorrectionThreshold + ")");
}
if (normalizedScore >= mAutoCorrectionThreshold) {
- mHaveCorrection = true;
+ if (DBG) {
+ Log.d(TAG, "Auto corrected by S-threthhold.");
+ }
+ mHaveAutoCorrection = true;
}
}
}
@@ -331,7 +339,10 @@ public class Suggest implements Dictionary.WordCallback {
canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i + 1));
}
if (canAdd) {
- mHaveCorrection = true;
+ if (DBG) {
+ Log.d(TAG, "Auto corrected by AUTOTEXT.");
+ }
+ mHaveAutoCorrection = true;
mSuggestions.add(i + 1, autoText);
i++;
}
@@ -374,7 +385,7 @@ public class Suggest implements Dictionary.WordCallback {
}
public boolean hasMinimalCorrection() {
- return mHaveCorrection;
+ return mHaveAutoCorrection;
}
private boolean compareCaseInsensitive(final String mLowerOriginalWord,
@@ -496,7 +507,7 @@ public class Suggest implements Dictionary.WordCallback {
}
public boolean isValidWord(final CharSequence word) {
- if (word == null || word.length() == 0) {
+ if (word == null || word.length() == 0 || mMainDict == null) {
return false;
}
return mMainDict.isValidWord(word)
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 5398b77b2..0fbbcdd91 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -124,7 +124,7 @@ public class SuggestedWords {
addWord(previousSuggestions.getWord(pos));
mIsCompletions = false;
mTypedWordValid = false;
- mHasMinimalSuggestion = (previousSize > 1);
+ mHasMinimalSuggestion = false;
return this;
}
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 56ad6c7aa..160948507 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -36,6 +36,8 @@ import java.text.SimpleDateFormat;
import java.util.Date;
public class Utils {
+ private static final String TAG = Utils.class.getSimpleName();
+ private static boolean DBG = LatinImeLogger.sDBG;
/**
* Cancel an {@link AsyncTask}.
@@ -96,6 +98,29 @@ public class Utils {
// || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
}
+
+ public static boolean shouldBlockedBySafetyNetForAutoCorrection(SuggestedWords suggestions) {
+ // Safety net for auto correction.
+ // Actually if we hit this safety net, it's actually a bug.
+ if (suggestions.size() <= 1 || suggestions.mTypedWordValid) return false;
+ CharSequence typedWord = suggestions.getWord(0);
+ CharSequence candidateWord = suggestions.getWord(1);
+ final int typedWordLength = typedWord.length();
+ final int maxEditDistanceOfNativeDictionary = typedWordLength < 5 ? 2 : typedWordLength / 2;
+ final int distance = Utils.editDistance(typedWord, candidateWord);
+ if (DBG) {
+ Log.d(TAG, "Autocorrected edit distance = " + distance
+ + ", " + maxEditDistanceOfNativeDictionary);
+ }
+ if (distance > maxEditDistanceOfNativeDictionary) {
+ Log.w(TAG, "(Error) The edit distance of this correction exceeds limit. "
+ + "Turning off auto-correction.");
+ return true;
+ } else {
+ return false;
+ }
+ }
+
/* package */ static class RingCharBuffer {
private static RingCharBuffer sRingCharBuffer = new RingCharBuffer();
private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC';
diff --git a/java/src/com/android/inputmethod/voice/RecognitionView.java b/java/src/com/android/inputmethod/voice/RecognitionView.java
index 12d0de852..98db9365f 100644
--- a/java/src/com/android/inputmethod/voice/RecognitionView.java
+++ b/java/src/com/android/inputmethod/voice/RecognitionView.java
@@ -16,9 +16,6 @@
package com.android.inputmethod.voice;
-import com.android.inputmethod.latin.R;
-
-import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -29,20 +26,21 @@ import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
-import android.util.TypedValue;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
-import android.view.ViewGroup.MarginLayoutParams;
+import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.inputmethod.latin.R;
+
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
-import java.util.ArrayList;
import java.util.List;
/**
@@ -58,81 +56,55 @@ public class RecognitionView {
private View mView;
private Context mContext;
- private ImageView mImage;
private TextView mText;
- private View mButton;
- private TextView mButtonText;
+ private ImageView mImage;
private View mProgress;
+ private SoundIndicator mSoundIndicator;
+ private Button mButton;
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() {
- @Override
- public void run() {
- if (mState != State.LISTENING) {
- return;
- }
-
- final float min = mMinMicrophoneLevel;
- final float max = mMaxMicrophoneLevel;
- final int maxLevel = mSpeakNow.size() - 1;
+ private static final int INIT = 0;
+ private static final int LISTENING = 1;
+ private static final int WORKING = 2;
+ private static final int READY = 3;
+
+ private int mState = INIT;
- int index = (int) ((mVolume - min) / (max - min) * maxLevel);
- final int level = Math.min(Math.max(0, index), maxLevel);
+ private final View mPopupLayout;
- if (level != mLevel) {
- mImage.setImageDrawable(mSpeakNow.get(level));
- mLevel = level;
- }
- mUiHandler.postDelayed(mUpdateVolumeRunnable, 50);
- }
- };
+ private final Drawable mListeningBorder;
+ private final Drawable mWorkingBorder;
+ private final Drawable mErrorBorder;
public RecognitionView(Context context, OnClickListener clickListener) {
mUiHandler = new Handler();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
+ 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);
+
+ mPopupLayout= mView.findViewById(R.id.popup_layout);
// 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));
+ mListeningBorder = r.getDrawable(R.drawable.vs_dialog_red);
+ mWorkingBorder = r.getDrawable(R.drawable.vs_dialog_blue);
+ mErrorBorder = r.getDrawable(R.drawable.vs_dialog_yellow);
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);
+ mProgress = mView.findViewById(R.id.progress);
+ mSoundIndicator = (SoundIndicator) mView.findViewById(R.id.sound_indicator);
+
+ mButton = (Button) 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;
}
@@ -146,9 +118,9 @@ public class RecognitionView {
@Override
public void run() {
// Restart the spinner
- if (mState == State.WORKING) {
- ((ProgressBar)mProgress).setIndeterminate(false);
- ((ProgressBar)mProgress).setIndeterminate(true);
+ if (mState == WORKING) {
+ ((ProgressBar) mProgress).setIndeterminate(false);
+ ((ProgressBar) mProgress).setIndeterminate(true);
}
}
});
@@ -158,48 +130,48 @@ public class RecognitionView {
mUiHandler.post(new Runnable() {
@Override
public void run() {
- prepareDialog(false, mContext.getText(R.string.voice_initializing), mInitializing,
- mContext.getText(R.string.cancel));
+ mState = INIT;
+ prepareDialog(mContext.getText(R.string.voice_initializing), mInitializing,
+ mContext.getText(R.string.cancel));
}
});
}
public void showListening() {
+ Log.d(TAG, "#showListening");
mUiHandler.post(new Runnable() {
@Override
public void run() {
- mState = State.LISTENING;
- prepareDialog(false, mContext.getText(R.string.voice_listening), mSpeakNow.get(0),
+ mState = LISTENING;
+ prepareDialog(mContext.getText(R.string.voice_listening), null,
mContext.getText(R.string.cancel));
}
});
- mUiHandler.postDelayed(mUpdateVolumeRunnable, 50);
}
- public void updateVoiceMeter(final float rmsdB) {
- mVolume = rmsdB;
+ public void updateVoiceMeter(float rmsdB) {
+ mSoundIndicator.setRmsdB(rmsdB);
}
public void showError(final String message) {
mUiHandler.post(new Runnable() {
@Override
public void run() {
- mState = State.READY;
- prepareDialog(false, message, mError, mContext.getText(R.string.ok));
+ mState = READY;
+ prepareDialog(message, mError, mContext.getText(R.string.ok));
}
- });
+ });
}
public void showWorking(
final ByteArrayOutputStream waveBuffer,
final int speechStartPosition,
final int speechEndPosition) {
-
mUiHandler.post(new Runnable() {
@Override
public void run() {
- mState = State.WORKING;
- prepareDialog(true, mContext.getText(R.string.voice_working), null, mContext
+ mState = WORKING;
+ prepareDialog(mContext.getText(R.string.voice_working), null, mContext
.getText(R.string.cancel));
final ShortBuffer buf = ByteBuffer.wrap(waveBuffer.toByteArray()).order(
ByteOrder.nativeOrder()).asShortBuffer();
@@ -207,21 +179,71 @@ public class RecognitionView {
waveBuffer.reset();
showWave(buf, speechStartPosition / 2, speechEndPosition / 2);
}
- });
+ });
}
- private void prepareDialog(boolean spinVisible, CharSequence text, Drawable image,
+ private void prepareDialog(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);
+ switch (mState) {
+ case INIT:
+ mText.setVisibility(View.GONE);
+
+ mProgress.setVisibility(View.GONE);
+
+ mImage.setVisibility(View.VISIBLE);
+ mImage.setImageResource(R.drawable.mic_slash);
+
+ mSoundIndicator.setVisibility(View.GONE);
+ mSoundIndicator.stop();
+
+ mPopupLayout.setBackgroundDrawable(mListeningBorder);
+ break;
+ case LISTENING:
+ mText.setVisibility(View.VISIBLE);
+ mText.setText(text);
+
+ mProgress.setVisibility(View.GONE);
+
+ mImage.setVisibility(View.GONE);
+
+ mSoundIndicator.setVisibility(View.VISIBLE);
+ mSoundIndicator.start();
+
+ mPopupLayout.setBackgroundDrawable(mListeningBorder);
+ break;
+ case WORKING:
+
+ mText.setVisibility(View.VISIBLE);
+ mText.setText(text);
+
+ mProgress.setVisibility(View.VISIBLE);
+
+ mImage.setVisibility(View.VISIBLE);
+
+ mSoundIndicator.setVisibility(View.GONE);
+ mSoundIndicator.stop();
+
+ mPopupLayout.setBackgroundDrawable(mWorkingBorder);
+ break;
+ case READY:
+ mText.setVisibility(View.VISIBLE);
+ mText.setText(text);
+
+ mProgress.setVisibility(View.GONE);
+
+ mImage.setVisibility(View.VISIBLE);
+ mImage.setImageResource(R.drawable.caution);
+
+ mSoundIndicator.setVisibility(View.GONE);
+ mSoundIndicator.stop();
+
+ mPopupLayout.setBackgroundDrawable(mErrorBorder);
+ break;
+ default:
+ Log.w(TAG, "Unknown state " + mState);
}
- mText.setText(text);
- mButtonText.setText(btnTxt);
+ mPopupLayout.requestLayout();
+ mButton.setText(btnTxt);
}
/**
@@ -248,7 +270,7 @@ public class RecognitionView {
*/
private void showWave(ShortBuffer waveBuffer, int startPosition, int endPosition) {
final int w = ((View) mImage.getParent()).getWidth();
- final int h = mImage.getHeight();
+ final int h = ((View) mImage.getParent()).getHeight();
if (w <= 0 || h <= 0) {
// view is not visible this time. Skip drawing.
return;
@@ -259,7 +281,7 @@ public class RecognitionView {
paint.setColor(0xFFFFFFFF); // 0xAARRGGBB
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
- paint.setAlpha(0x90);
+ paint.setAlpha(80);
final PathEffect effect = new CornerPathEffect(3);
paint.setPathEffect(effect);
@@ -281,7 +303,7 @@ public class RecognitionView {
final int count = (endIndex - startIndex) / numSamplePerWave;
final float deltaX = 1.0f * w / count;
- int yMax = h / 2 - 8;
+ int yMax = h / 2;
Path path = new Path();
c.translate(0, yMax);
float x = 0;
@@ -295,37 +317,20 @@ public class RecognitionView {
path.lineTo(x, y);
}
if (deltaX > 4) {
- paint.setStrokeWidth(3);
+ paint.setStrokeWidth(2);
} else {
- paint.setStrokeWidth(Math.max(1, (int) (deltaX -.05)));
+ paint.setStrokeWidth(Math.max(0, (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_PX,
- -h , 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() {
@Override
public void run() {
- mState = State.READY;
- exitWorking();
+ mSoundIndicator.stop();
}
- });
- }
-
- private void exitWorking() {
- mProgress.setVisibility(View.GONE);
- mImage.setVisibility(View.VISIBLE);
+ });
}
}
diff --git a/java/src/com/android/inputmethod/voice/SoundIndicator.java b/java/src/com/android/inputmethod/voice/SoundIndicator.java
new file mode 100644
index 000000000..543290b32
--- /dev/null
+++ b/java/src/com/android/inputmethod/voice/SoundIndicator.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2011 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.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import com.android.inputmethod.latin.R;
+
+/**
+ * A widget which shows the volume of audio using a microphone icon
+ */
+public class SoundIndicator extends ImageView {
+ @SuppressWarnings("unused")
+ private static final String TAG = "SoundIndicator";
+
+ private static final float UP_SMOOTHING_FACTOR = 0.9f;
+ private static final float DOWN_SMOOTHING_FACTOR = 0.4f;
+
+ private static final float AUDIO_METER_MIN_DB = 7.0f;
+ private static final float AUDIO_METER_DB_RANGE = 20.0f;
+
+ private static final long FRAME_DELAY = 50;
+
+ private Bitmap mDrawingBuffer;
+ private Canvas mBufferCanvas;
+ private Bitmap mEdgeBitmap;
+ private float mLevel = 0.0f;
+ private Drawable mFrontDrawable;
+ private Paint mClearPaint;
+ private Paint mMultPaint;
+ private int mEdgeBitmapOffset;
+
+ private Handler mHandler;
+
+ private Runnable mDrawFrame = new Runnable() {
+ public void run() {
+ invalidate();
+ mHandler.postDelayed(mDrawFrame, FRAME_DELAY);
+ }
+ };
+
+ public SoundIndicator(Context context) {
+ this(context, null);
+ }
+
+ public SoundIndicator(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ mFrontDrawable = getDrawable();
+ BitmapDrawable edgeDrawable =
+ (BitmapDrawable) context.getResources().getDrawable(R.drawable.vs_popup_mic_edge);
+ mEdgeBitmap = edgeDrawable.getBitmap();
+ mEdgeBitmapOffset = mEdgeBitmap.getHeight() / 2;
+
+ mDrawingBuffer =
+ Bitmap.createBitmap(mFrontDrawable.getIntrinsicWidth(),
+ mFrontDrawable.getIntrinsicHeight(), Config.ARGB_8888);
+
+ mBufferCanvas = new Canvas(mDrawingBuffer);
+
+ // Initialize Paints.
+ mClearPaint = new Paint();
+ mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+
+ mMultPaint = new Paint();
+ mMultPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
+
+ mHandler = new Handler();
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ //super.onDraw(canvas);
+
+ float w = getWidth();
+ float h = getHeight();
+
+ // Clear the buffer canvas
+ mBufferCanvas.drawRect(0, 0, w, h, mClearPaint);
+
+ // Set its clip so we don't draw the front image all the way to the top
+ Rect clip = new Rect(0,
+ (int) ((1.0 - mLevel) * (h + mEdgeBitmapOffset)) - mEdgeBitmapOffset,
+ (int) w,
+ (int) h);
+
+ mBufferCanvas.save();
+ mBufferCanvas.clipRect(clip);
+
+ // Draw the front image
+ mFrontDrawable.setBounds(new Rect(0, 0, (int) w, (int) h));
+ mFrontDrawable.draw(mBufferCanvas);
+
+ mBufferCanvas.restore();
+
+ // Draw the edge image on top of the buffer image with a multiply mode
+ mBufferCanvas.drawBitmap(mEdgeBitmap, 0, clip.top, mMultPaint);
+
+ // Draw the buffer image (on top of the background image)
+ canvas.drawBitmap(mDrawingBuffer, 0, 0, null);
+ }
+
+ /**
+ * Sets the sound level
+ *
+ * @param rmsdB The level of the sound, in dB.
+ */
+ public void setRmsdB(float rmsdB) {
+ float level = ((rmsdB - AUDIO_METER_MIN_DB) / AUDIO_METER_DB_RANGE);
+
+ level = Math.min(Math.max(0.0f, level), 1.0f);
+
+ // We smooth towards the new level
+ if (level > mLevel) {
+ mLevel = (level - mLevel) * UP_SMOOTHING_FACTOR + mLevel;
+ } else {
+ mLevel = (level - mLevel) * DOWN_SMOOTHING_FACTOR + mLevel;
+ }
+ invalidate();
+ }
+
+ public void start() {
+ mHandler.post(mDrawFrame);
+ }
+
+ public void stop() {
+ mHandler.removeCallbacks(mDrawFrame);
+ }
+}
diff --git a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
index 1ff918315..fe6e318c9 100644
--- a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
+++ b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.voice;
+import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.latin.EditingUtils;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinIME.UIHandler;
@@ -29,6 +30,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.res.Configuration;
import android.net.Uri;
import android.os.IBinder;
import android.preference.PreferenceManager;
@@ -77,6 +79,9 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
// dialog is already showing a voice search button.
private static final String IME_OPTION_NO_MICROPHONE = "nm";
+ @SuppressWarnings("unused")
+ private static final String TAG = "VoiceIMEConnector";
+
private boolean mAfterVoiceInput;
private boolean mHasUsedVoiceInput;
private boolean mHasUsedVoiceInputUnsupportedLocale;
@@ -91,7 +96,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
private boolean mVoiceInputHighlighted;
private InputMethodManager mImm;
- private LatinIME mContext;
+ private LatinIME mService;
private AlertDialog mVoiceWarningDialog;
private VoiceInput mVoiceInput;
private final VoiceResults mVoiceResults = new VoiceResults();
@@ -111,21 +116,19 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
return sInstance;
}
- private void initInternal(LatinIME context, SharedPreferences prefs, UIHandler h) {
- mContext = context;
+ private void initInternal(LatinIME service, SharedPreferences prefs, UIHandler h) {
+ mService = service;
mHandler = h;
- mImm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+ mImm = (InputMethodManager) service.getSystemService(Context.INPUT_METHOD_SERVICE);
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
if (VOICE_INSTALLED) {
- mVoiceInput = new VoiceInput(context, this);
- mHints = new Hints(context, prefs, new Hints.Display() {
+ mVoiceInput = new VoiceInput(service, this);
+ mHints = new Hints(service, prefs, new Hints.Display() {
@Override
public void showHint(int viewResource) {
- LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- View view = inflater.inflate(viewResource, null);
- mContext.setCandidatesView(view);
- mContext.setCandidatesViewShown(true);
+ View view = LayoutInflater.from(mService).inflate(viewResource, null);
+ mService.setCandidatesView(view);
+ mService.setCandidatesViewShown(true);
mIsShowingHint = true;
}
});
@@ -161,23 +164,22 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mVoiceInput.flushAllTextModificationCounters();
// send this intent AFTER logging any prior aggregated edits.
mVoiceInput.logTextModifiedByChooseSuggestion(suggestion.toString(), index,
- wordSeparators, mContext.getCurrentInputConnection());
+ wordSeparators, mService.getCurrentInputConnection());
}
}
- private void showVoiceWarningDialog(final boolean swipe, IBinder token,
- final boolean configurationChanging) {
+ private void showVoiceWarningDialog(final boolean swipe, IBinder token) {
if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
return;
}
- AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+ AlertDialog.Builder builder = new AlertDialog.Builder(mService);
builder.setCancelable(true);
builder.setIcon(R.drawable.ic_mic_dialog);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
mVoiceInput.logKeyboardWarningDialogOk();
- reallyStartListening(swipe, configurationChanging);
+ reallyStartListening(swipe);
}
});
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@@ -199,13 +201,13 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
final CharSequence message;
if (mLocaleSupportedForVoiceInput) {
message = TextUtils.concat(
- mContext.getText(R.string.voice_warning_may_not_understand), "\n\n",
- mContext.getText(R.string.voice_warning_how_to_turn_off));
+ mService.getText(R.string.voice_warning_may_not_understand), "\n\n",
+ mService.getText(R.string.voice_warning_how_to_turn_off));
} else {
message = TextUtils.concat(
- mContext.getText(R.string.voice_warning_locale_not_supported), "\n\n",
- mContext.getText(R.string.voice_warning_may_not_understand), "\n\n",
- mContext.getText(R.string.voice_warning_how_to_turn_off));
+ mService.getText(R.string.voice_warning_locale_not_supported), "\n\n",
+ mService.getText(R.string.voice_warning_may_not_understand), "\n\n",
+ mService.getText(R.string.voice_warning_how_to_turn_off));
}
builder.setMessage(message);
@@ -296,7 +298,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
}
public void showPunctuationHintIfNecessary() {
- InputConnection ic = mContext.getCurrentInputConnection();
+ InputConnection ic = mService.getCurrentInputConnection();
if (!mImmediatelyAfterVoiceInput && mAfterVoiceInput && ic != null) {
if (mHints.showPunctuationHintIfNecessary(ic)) {
mVoiceInput.logPunctuationHintDisplayed();
@@ -364,17 +366,17 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
}
private void revertVoiceInput() {
- InputConnection ic = mContext.getCurrentInputConnection();
+ InputConnection ic = mService.getCurrentInputConnection();
if (ic != null) ic.commitText("", 1);
- mContext.updateSuggestions();
+ mService.updateSuggestions();
mVoiceInputHighlighted = false;
}
public void commitVoiceInput() {
if (VOICE_INSTALLED && mVoiceInputHighlighted) {
- InputConnection ic = mContext.getCurrentInputConnection();
+ InputConnection ic = mService.getCurrentInputConnection();
if (ic != null) ic.finishComposingText();
- mContext.updateSuggestions();
+ mService.updateSuggestions();
mVoiceInputHighlighted = false;
}
}
@@ -394,7 +396,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
if (mShowingVoiceSuggestions) {
// Retain the replaced word in the alternatives array.
String wordToBeReplaced = EditingUtils.getWordAtCursor(
- mContext.getCurrentInputConnection(), wordSeparators);
+ mService.getCurrentInputConnection(), wordSeparators);
if (!mWordToSuggestions.containsKey(wordToBeReplaced)) {
wordToBeReplaced = wordToBeReplaced.toLowerCase();
}
@@ -438,8 +440,8 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
builder.addWords(suggestions);
}
builder.setTypedWordValid(true).setHasMinimalSuggestion(true);
- mContext.setSuggestions(builder.build());
- mContext.setCandidatesViewShown(true);
+ mService.setSuggestions(builder.build());
+ mService.setCandidatesViewShown(true);
return true;
}
return false;
@@ -486,15 +488,15 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mAfterVoiceInput = true;
mImmediatelyAfterVoiceInput = true;
- InputConnection ic = mContext.getCurrentInputConnection();
- if (!mContext.isFullscreenMode()) {
+ InputConnection ic = mService.getCurrentInputConnection();
+ if (!mService.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);
}
}
- mContext.vibrate();
+ mService.vibrate();
final List<CharSequence> nBest = new ArrayList<CharSequence>();
for (String c : mVoiceResults.candidates) {
@@ -511,7 +513,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mHints.registerVoiceResult(bestResult);
if (ic != null) ic.beginBatchEdit(); // To avoid extra updates on committing older text
- mContext.commitTyped(ic);
+ mService.commitTyped(ic);
EditingUtils.appendText(ic, bestResult);
if (ic != null) ic.endBatchEdit();
@@ -520,22 +522,38 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
onCancelVoice();
}
- public void switchToRecognitionStatusView(final boolean configurationChanging) {
- final boolean configChanged = configurationChanging;
+ public void switchToRecognitionStatusView(final Configuration configuration) {
mHandler.post(new Runnable() {
@Override
public void run() {
- mContext.setCandidatesViewShown(false);
+ mService.setCandidatesViewShown(false);
mRecognizing = true;
+ mVoiceInput.newView();
View v = mVoiceInput.getView();
+
ViewParent p = v.getParent();
if (p != null && p instanceof ViewGroup) {
- ((ViewGroup)p).removeView(v);
+ ((ViewGroup) p).removeView(v);
}
- mContext.setInputView(v);
- mContext.updateInputViewShown();
- if (configChanged) {
- mVoiceInput.onConfigurationChanged();
+
+ View keyboardView = KeyboardSwitcher.getInstance().getInputView();
+
+ // The full height of the keyboard is difficult to calculate
+ // as the dimension is expressed in "mm" and not in "pixel"
+ // As we add mm, we don't know how the rounding is going to work
+ // thus we may end up with few pixels extra (or less).
+ if (keyboardView != null) {
+ int h = keyboardView.getHeight();
+ if (h > 0) {
+ View popupLayout = v.findViewById(R.id.popup_layout);
+ popupLayout.getLayoutParams().height = h;
+ }
+ }
+ mService.setInputView(v);
+ mService.updateInputViewShown();
+
+ if (configuration != null) {
+ mVoiceInput.onConfigurationChanged(configuration);
}
}});
}
@@ -547,7 +565,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
*/
}
- private void reallyStartListening(boolean swipe, final boolean configurationChanging) {
+ private void reallyStartListening(boolean swipe) {
if (!VOICE_INSTALLED) {
return;
}
@@ -555,7 +573,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
// 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(mContext).edit();
+ PreferenceManager.getDefaultSharedPreferences(mService).edit();
editor.putBoolean(PREF_HAS_USED_VOICE_INPUT, true);
SharedPreferencesCompat.apply(editor);
mHasUsedVoiceInput = true;
@@ -565,34 +583,32 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
// 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(mContext).edit();
+ PreferenceManager.getDefaultSharedPreferences(mService).edit();
editor.putBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, true);
SharedPreferencesCompat.apply(editor);
mHasUsedVoiceInputUnsupportedLocale = true;
}
// Clear N-best suggestions
- mContext.clearSuggestions();
+ mService.clearSuggestions();
FieldContext context = makeFieldContext();
mVoiceInput.startListening(context, swipe);
- switchToRecognitionStatusView(configurationChanging);
+ switchToRecognitionStatusView(null);
}
- public void startListening(final boolean swipe, IBinder token,
- final boolean configurationChanging) {
+ public void startListening(final boolean swipe, IBinder token) {
// TODO: remove swipe which is no longer used.
if (VOICE_INSTALLED) {
if (needsToShowWarningDialog()) {
// Calls reallyStartListening if user clicks OK, does nothing if user clicks Cancel.
- showVoiceWarningDialog(swipe, token, configurationChanging);
+ showVoiceWarningDialog(swipe, token);
} else {
- reallyStartListening(swipe, configurationChanging);
+ reallyStartListening(swipe);
}
}
}
-
private boolean fieldCanDoVoice(FieldContext fieldContext) {
return !mPasswordText
&& mVoiceInput != null
@@ -603,7 +619,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext)
&& !(attribute != null
&& IME_OPTION_NO_MICROPHONE.equals(attribute.privateImeOptions))
- && SpeechRecognizer.isRecognitionAvailable(mContext);
+ && SpeechRecognizer.isRecognitionAvailable(mService);
}
public void loadSettings(EditorInfo attribute, SharedPreferences sp) {
@@ -616,10 +632,10 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
if (VOICE_INSTALLED) {
final String voiceMode = sp.getString(PREF_VOICE_MODE,
- mContext.getString(R.string.voice_mode_main));
- mVoiceButtonEnabled = !voiceMode.equals(mContext.getString(R.string.voice_mode_off))
+ mService.getString(R.string.voice_mode_main));
+ mVoiceButtonEnabled = !voiceMode.equals(mService.getString(R.string.voice_mode_off))
&& shouldShowVoiceButton(makeFieldContext(), attribute);
- mVoiceButtonOnPrimary = voiceMode.equals(mContext.getString(R.string.voice_mode_main));
+ mVoiceButtonOnPrimary = voiceMode.equals(mService.getString(R.string.voice_mode_main));
}
}
@@ -632,9 +648,14 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
public void onStartInputView(IBinder token) {
// If IME is in voice mode, but still needs to show the voice warning dialog,
// keep showing the warning.
- if (mSubtypeSwitcher.isVoiceMode() && needsToShowWarningDialog() && token != null) {
- showVoiceWarningDialog(false, token, false);
+ if (mSubtypeSwitcher.isVoiceMode() && token != null) {
+ // Close keyboard view if it is been shown.
+ if (KeyboardSwitcher.getInstance().isInputViewShown())
+ KeyboardSwitcher.getInstance().getInputView().purgeKeyboardAndClosing();
+ startListening(false, token);
}
+ // If we have no token, onAttachedToWindow will take care of showing dialog and start
+ // listening.
}
public void onAttachedToWindow() {
@@ -643,9 +664,9 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mSubtypeSwitcher.setVoiceInput(mVoiceInput);
}
- public void onConfigurationChanged(boolean configurationChanging) {
+ public void onConfigurationChanged(Configuration configuration) {
if (mRecognizing) {
- switchToRecognitionStatusView(configurationChanging);
+ switchToRecognitionStatusView(configuration);
}
}
@@ -664,7 +685,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
// onCurrentInputMethodSubtypeChanged() will be called first. LatinIME will know
// that it's in keyboard mode and SubtypeSwitcher will call onCancelVoice().
mRecognizing = false;
- mContext.switchToKeyboardView();
+ mService.switchToKeyboardView();
}
}
}
@@ -682,8 +703,8 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
public FieldContext makeFieldContext() {
SubtypeSwitcher switcher = SubtypeSwitcher.getInstance();
- return new FieldContext(mContext.getCurrentInputConnection(),
- mContext.getCurrentInputEditorInfo(), switcher.getInputLocaleStr(),
+ return new FieldContext(mService.getCurrentInputConnection(),
+ mService.getCurrentInputEditorInfo(), switcher.getInputLocaleStr(),
switcher.getEnabledLanguages());
}
diff --git a/java/src/com/android/inputmethod/voice/VoiceInput.java b/java/src/com/android/inputmethod/voice/VoiceInput.java
index f77b4dd0d..ffa349fde 100644
--- a/java/src/com/android/inputmethod/voice/VoiceInput.java
+++ b/java/src/com/android/inputmethod/voice/VoiceInput.java
@@ -22,6 +22,7 @@ import com.android.inputmethod.latin.R;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -129,12 +130,17 @@ public class VoiceInput implements OnClickListener {
private final static int MSG_CLOSE_ERROR_DIALOG = 1;
+ private final static int MSG_RESET = 2;
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- if (msg.what == MSG_CLOSE_ERROR_DIALOG) {
+ if (msg.what == MSG_RESET || msg.what == MSG_CLOSE_ERROR_DIALOG) {
mState = DEFAULT;
mRecognitionView.finish();
+ }
+
+ if (msg.what == MSG_CLOSE_ERROR_DIALOG) {
mUiListener.onCancelVoice();
}
}
@@ -277,8 +283,9 @@ public class VoiceInput implements OnClickListener {
* 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() {
+ public void onConfigurationChanged(Configuration configuration) {
mRecognitionView.restoreState();
+ mRecognitionView.getView().dispatchConfigurationChanged(configuration);
}
/**
@@ -509,7 +516,7 @@ public class VoiceInput implements OnClickListener {
mState = DEFAULT;
// Remove all pending tasks (e.g., timers to cancel voice input)
- mHandler.removeMessages(MSG_CLOSE_ERROR_DIALOG);
+ mHandler.removeMessages(MSG_RESET);
mSpeechRecognizer.cancel();
mUiListener.onCancelVoice();