aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java5
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java15
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java14
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java2
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java89
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java156
-rw-r--r--java/src/com/android/inputmethod/latin/CandidateView.java6
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java24
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeSwitcher.java2
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java13
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java43
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java41
12 files changed, 305 insertions, 105 deletions
diff --git a/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java b/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java
index d40728d25..bf2512d7b 100644
--- a/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java
+++ b/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java
@@ -271,9 +271,10 @@ public class Recorrection implements SharedPreferences.OnSharedPreferenceChangeL
// but always use the default setting defined in the resources.
if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) {
mRecorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
- res.getBoolean(R.bool.config_default_recorrection_enabled));
+ res.getBoolean(R.bool.config_default_compat_recorrection_enabled));
} else {
- mRecorrectionEnabled = res.getBoolean(R.bool.config_default_recorrection_enabled);
+ mRecorrectionEnabled =
+ res.getBoolean(R.bool.config_default_compat_recorrection_enabled);
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 811470c26..21477a992 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -280,7 +280,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mSymbolsKeyboardId = getKeyboardId(editorInfo, true, false, settingsValues);
mSymbolsShiftedKeyboardId = getKeyboardId(editorInfo, true, true, settingsValues);
setKeyboard(getKeyboard(mSavedKeyboardState.getKeyboardId()));
- updateShiftState();
} catch (RuntimeException e) {
Log.w(TAG, "loading keyboard failed: " + mMainKeyboardId, e);
LatinImeLogger.logOnException(mMainKeyboardId.toString(), e);
@@ -331,6 +330,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
final boolean localeChanged = (oldKeyboard == null)
|| !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
+ updateShiftState();
}
private int getSwitchState(KeyboardId id) {
@@ -543,11 +543,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
private void setAutomaticTemporaryUpperCase() {
- LatinKeyboard latinKeyboard = getLatinKeyboard();
- if (latinKeyboard != null) {
- latinKeyboard.setAutomaticTemporaryUpperCase();
- mKeyboardView.invalidateAllKeys();
+ if (mKeyboardView == null) return;
+ final Keyboard keyboard = mKeyboardView.getKeyboard();
+ if (keyboard != null) {
+ keyboard.setAutomaticTemporaryUpperCase();
}
+ mKeyboardView.invalidateAllKeys();
}
/**
@@ -559,7 +560,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
Log.d(TAG, "updateShiftState:"
+ " autoCaps=" + mInputMethodService.getCurrentAutoCapsState()
+ " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
- + " shiftKeyState=" + shiftKeyState);
+ + " shiftKeyState=" + shiftKeyState
+ + " isAlphabetMode=" + isAlphabetMode()
+ + " isShiftLocked=" + isShiftLocked());
if (isAlphabetMode()) {
if (!isShiftLocked() && !shiftKeyState.isIgnoring()) {
if (shiftKeyState.isReleasing() && mInputMethodService.getCurrentAutoCapsState()) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 2df2994f6..bc021a690 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -83,6 +83,11 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// HORIZONTAL ELLIPSIS "...", character for popup hint.
private static final String POPUP_HINT_CHAR = "\u2026";
+ // Margin between the label and the icon on a key that has both of them.
+ // Specified by the fraction of the key width.
+ // TODO: Use resource parameter for this value.
+ private static final float LABEL_ICON_MARGIN = 0.05f;
+
// Main keyboard
private Keyboard mKeyboard;
private final KeyDrawParams mKeyDrawParams;
@@ -538,11 +543,13 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
positionX = centerX - labelCharWidth * 7 / 4;
paint.setTextAlign(Align.LEFT);
} else if (key.hasLabelWithIconLeft() && icon != null) {
- labelWidth = getLabelWidth(label, paint) + icon.getIntrinsicWidth();
+ labelWidth = getLabelWidth(label, paint) + icon.getIntrinsicWidth()
+ + (int)(LABEL_ICON_MARGIN * keyWidth);
positionX = centerX + labelWidth / 2;
paint.setTextAlign(Align.RIGHT);
} else if (key.hasLabelWithIconRight() && icon != null) {
- labelWidth = getLabelWidth(label, paint) + icon.getIntrinsicWidth();
+ labelWidth = getLabelWidth(label, paint) + icon.getIntrinsicWidth()
+ + (int)(LABEL_ICON_MARGIN * keyWidth);
positionX = centerX - labelWidth / 2;
paint.setTextAlign(Align.LEFT);
} else {
@@ -734,7 +741,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
canvas.translate(-x, -y);
}
- private static void drawHorizontalLine(Canvas canvas, float y, float w, int color, Paint paint) {
+ private static void drawHorizontalLine(Canvas canvas, float y, float w, int color,
+ Paint paint) {
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1.0f);
paint.setColor(color);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java
index 0cde4e5b5..fd98456a8 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java
@@ -21,7 +21,7 @@ import android.util.Log;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
public class KeyboardShiftState {
- private static final String TAG = "KeyboardShiftState";
+ private static final String TAG = KeyboardShiftState.class.getSimpleName();
private static final boolean DEBUG = KeyboardSwitcher.DEBUG_STATE;
private static final int NORMAL = 0;
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
index 2d50a6f46..3da670e2e 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
@@ -25,7 +25,6 @@ import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
-import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -55,66 +54,6 @@ public class BinaryDictionaryFileDumper {
}
/**
- * Escapes a string for any characters that may be suspicious for a file or directory name.
- *
- * Concretely this does a sort of URL-encoding except it will encode everything that's not
- * alphanumeric or underscore. (true URL-encoding leaves alone characters like '*', which
- * we cannot allow here)
- */
- // TODO: create a unit test for this method
- private static String replaceFileNameDangerousCharacters(String name) {
- // This assumes '%' is fully available as a non-separator, normal
- // character in a file name. This is probably true for all file systems.
- final StringBuilder sb = new StringBuilder();
- for (int i = 0; i < name.length(); ++i) {
- final int codePoint = name.codePointAt(i);
- if (Character.isLetterOrDigit(codePoint) || '_' == codePoint) {
- sb.appendCodePoint(codePoint);
- } else {
- sb.append('%');
- sb.append(Integer.toHexString(codePoint));
- }
- }
- return sb.toString();
- }
-
- /**
- * Find out the cache directory associated with a specific locale.
- */
- private static String getCacheDirectoryForLocale(Locale locale, Context context) {
- final String relativeDirectoryName = replaceFileNameDangerousCharacters(locale.toString());
- final String absoluteDirectoryName = context.getFilesDir() + File.separator
- + relativeDirectoryName;
- final File directory = new File(absoluteDirectoryName);
- if (!directory.exists()) {
- if (!directory.mkdirs()) {
- Log.e(TAG, "Could not create the directory for locale" + locale);
- }
- }
- return absoluteDirectoryName;
- }
-
- /**
- * Generates a file name for the id and locale passed as an argument.
- *
- * In the current implementation the file name returned will always be unique for
- * any id/locale pair, but please do not expect that the id can be the same for
- * different dictionaries with different locales. An id should be unique for any
- * dictionary.
- * The file name is pretty much an URL-encoded version of the id inside a directory
- * named like the locale, except it will also escape characters that look dangerous
- * to some file systems.
- * @param id the id of the dictionary for which to get a file name
- * @param locale the locale for which to get the file name
- * @param context the context to use for getting the directory
- * @return the name of the file to be created
- */
- private static String getCacheFileName(String id, Locale locale, Context context) {
- final String fileName = replaceFileNameDangerousCharacters(id);
- return getCacheDirectoryForLocale(locale, context) + File.separator + fileName;
- }
-
- /**
* Return for a given locale or dictionary id the provider URI to get the dictionary.
*/
private static Uri getProviderUri(String path) {
@@ -149,32 +88,32 @@ public class BinaryDictionaryFileDumper {
}
/**
- * Queries a content provider for dictionary data for some locale and returns the file addresses
+ * Queries a content provider for dictionary data for some locale and cache the returned files
*
- * This will query a content provider for dictionary data for a given locale, and return
- * the addresses of a file set the members of which are suitable to be mmap'ed. It will copy
- * them to local storage if needed.
- * It should also check the dictionary versions to avoid unnecessary copies but this is
- * still in TODO state.
- * This will make the data from the content provider the cached dictionary for this locale,
- * overwriting any previous cached data.
+ * This will query a content provider for dictionary data for a given locale, and copy the
+ * files locally so that they can be mmap'ed. This may overwrite previously cached dictionaries
+ * with newer versions if a newer version is made available by the content provider.
* @returns the addresses of the files, or null if no data could be obtained.
* @throw FileNotFoundException if the provider returns non-existent data.
* @throw IOException if the provider-returned data could not be read.
*/
- public static List<AssetFileAddress> getDictSetFromContentProvider(final Locale locale,
+ public static List<AssetFileAddress> cacheDictionariesFromContentProvider(final Locale locale,
final Context context) throws FileNotFoundException, IOException {
final ContentResolver resolver = context.getContentResolver();
final List<String> idList = getDictIdList(locale, context);
final List<AssetFileAddress> fileAddressList = new ArrayList<AssetFileAddress>();
for (String id : idList) {
- final Uri dictionaryPackUri = getProviderUri(id);
+ final Uri wordListUri = getProviderUri(id);
final AssetFileDescriptor afd =
- resolver.openAssetFileDescriptor(dictionaryPackUri, "r");
+ resolver.openAssetFileDescriptor(wordListUri, "r");
if (null == afd) continue;
final String fileName = copyFileTo(afd.createInputStream(),
- getCacheFileName(id, locale, context));
+ BinaryDictionaryGetter.getCacheFileName(id, locale, context));
afd.close();
+ if (0 >= resolver.delete(wordListUri, null, null)) {
+ // I'd rather not print the word list ID to the log here out of security concerns
+ Log.e(TAG, "Could not have the dictionary pack delete a word list");
+ }
fileAddressList.add(AssetFileAddress.makeFromFileName(fileName));
}
return fileAddressList;
@@ -192,7 +131,9 @@ public class BinaryDictionaryFileDumper {
final Locale savedLocale = Utils.setSystemLocale(res, locale);
final InputStream stream = res.openRawResource(resource);
Utils.setSystemLocale(res, savedLocale);
- return copyFileTo(stream, getCacheFileName(Integer.toString(resource), locale, context));
+ return copyFileTo(stream,
+ BinaryDictionaryGetter.getCacheFileName(Integer.toString(resource),
+ locale, context));
}
/**
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 4b1c05adf..360cf21ca 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -17,13 +17,17 @@
package com.android.inputmethod.latin;
import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.util.Log;
+import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -37,10 +41,105 @@ class BinaryDictionaryGetter {
*/
private static final String TAG = BinaryDictionaryGetter.class.getSimpleName();
+ /**
+ * Name of the common preferences name to know which word list are on and which are off.
+ */
+ private static final String COMMON_PREFERENCES_NAME = "LatinImeDictPrefs";
+
// Prevents this from being instantiated
private BinaryDictionaryGetter() {}
/**
+ * Returns whether we may want to use this character as part of a file name.
+ *
+ * This basically only accepts ascii letters and numbers, and rejects everything else.
+ */
+ private static boolean isFileNameCharacter(int codePoint) {
+ if (codePoint >= 0x30 && codePoint <= 0x39) return true; // Digit
+ if (codePoint >= 0x41 && codePoint <= 0x5A) return true; // Uppercase
+ if (codePoint >= 0x61 && codePoint <= 0x7A) return true; // Lowercase
+ return codePoint == '_'; // Underscore
+ }
+
+ /**
+ * Escapes a string for any characters that may be suspicious for a file or directory name.
+ *
+ * Concretely this does a sort of URL-encoding except it will encode everything that's not
+ * alphanumeric or underscore. (true URL-encoding leaves alone characters like '*', which
+ * we cannot allow here)
+ */
+ // TODO: create a unit test for this method
+ private static String replaceFileNameDangerousCharacters(final String name) {
+ // This assumes '%' is fully available as a non-separator, normal
+ // character in a file name. This is probably true for all file systems.
+ final StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < name.length(); ++i) {
+ final int codePoint = name.codePointAt(i);
+ if (isFileNameCharacter(codePoint)) {
+ sb.appendCodePoint(codePoint);
+ } else {
+ // 6 digits - unicode is limited to 21 bits
+ sb.append(String.format((Locale)null, "%%%1$06x", codePoint));
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Reverse escaping done by replaceFileNameDangerousCharacters.
+ */
+ private static String getWordListIdFromFileName(final String fname) {
+ final StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < fname.length(); ++i) {
+ final int codePoint = fname.codePointAt(i);
+ if ('%' != codePoint) {
+ sb.appendCodePoint(codePoint);
+ } else {
+ final int encodedCodePoint = Integer.parseInt(fname.substring(i + 1, i + 7), 16);
+ i += 6;
+ sb.appendCodePoint(encodedCodePoint);
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Find out the cache directory associated with a specific locale.
+ */
+ private static String getCacheDirectoryForLocale(Locale locale, Context context) {
+ final String relativeDirectoryName = replaceFileNameDangerousCharacters(locale.toString());
+ final String absoluteDirectoryName = context.getFilesDir() + File.separator
+ + relativeDirectoryName;
+ final File directory = new File(absoluteDirectoryName);
+ if (!directory.exists()) {
+ if (!directory.mkdirs()) {
+ Log.e(TAG, "Could not create the directory for locale" + locale);
+ }
+ }
+ return absoluteDirectoryName;
+ }
+
+ /**
+ * Generates a file name for the id and locale passed as an argument.
+ *
+ * In the current implementation the file name returned will always be unique for
+ * any id/locale pair, but please do not expect that the id can be the same for
+ * different dictionaries with different locales. An id should be unique for any
+ * dictionary.
+ * The file name is pretty much an URL-encoded version of the id inside a directory
+ * named like the locale, except it will also escape characters that look dangerous
+ * to some file systems.
+ * @param id the id of the dictionary for which to get a file name
+ * @param locale the locale for which to get the file name
+ * @param context the context to use for getting the directory
+ * @return the name of the file to be created
+ */
+ public static String getCacheFileName(String id, Locale locale, Context context) {
+ final String fileName = replaceFileNameDangerousCharacters(id);
+ return getCacheDirectoryForLocale(locale, context) + File.separator + fileName;
+ }
+
+ /**
* Returns a file address from a resource, or null if it cannot be opened.
*/
private static AssetFileAddress loadFallbackResource(final Context context,
@@ -60,6 +159,48 @@ class BinaryDictionaryGetter {
}
/**
+ * Returns the list of cached files for a specific locale.
+ *
+ * @param locale the locale to find the dictionary files for.
+ * @param context the context on which to open the files upon.
+ * @return a list of binary dictionary files, which may be null but may not be empty.
+ */
+ private static List<AssetFileAddress> getCachedDictionaryList(final Locale locale,
+ final Context context) {
+ final String directoryName = getCacheDirectoryForLocale(locale, context);
+ final File[] cacheFiles = new File(directoryName).listFiles();
+ // TODO: Never return null. Fallback on the built-in dictionary, and if that's
+ // not present or disabled, then return an empty list.
+ if (null == cacheFiles) return null;
+
+ final SharedPreferences dictPackSettings;
+ try {
+ final String dictPackName = context.getString(R.string.dictionary_pack_package_name);
+ final Context dictPackContext = context.createPackageContext(dictPackName, 0);
+ dictPackSettings = dictPackContext.getSharedPreferences(COMMON_PREFERENCES_NAME,
+ Context.MODE_WORLD_READABLE | Context.MODE_MULTI_PROCESS);
+ } catch (NameNotFoundException e) {
+ // The dictionary pack is not installed...
+ // TODO: fallback on the built-in dict, see the TODO above
+ Log.e(TAG, "Could not find a dictionary pack");
+ return null;
+ }
+
+ final ArrayList<AssetFileAddress> fileList = new ArrayList<AssetFileAddress>();
+ for (File f : cacheFiles) {
+ final String wordListId = getWordListIdFromFileName(f.getName());
+ final boolean isActive = dictPackSettings.getBoolean(wordListId, true);
+ if (!isActive) continue;
+ if (f.canRead()) {
+ fileList.add(AssetFileAddress.makeFromFileName(f.getPath()));
+ } else {
+ Log.e(TAG, "Found a cached dictionary file but cannot read it");
+ }
+ }
+ return fileList.size() > 0 ? fileList : null;
+ }
+
+ /**
* Returns a list of file addresses for a given locale, trying relevant methods in order.
*
* Tries to get binary dictionaries from various sources, in order:
@@ -71,13 +212,16 @@ class BinaryDictionaryGetter {
* - Returns null.
* @return The address of a valid file, or null.
*/
- public static List<AssetFileAddress> getDictionaryFiles(Locale locale, Context context,
- int fallbackResId) {
+ public static List<AssetFileAddress> getDictionaryFiles(final Locale locale,
+ final Context context, final int fallbackResId) {
try {
- List<AssetFileAddress> listFromContentProvider =
- BinaryDictionaryFileDumper.getDictSetFromContentProvider(locale, context);
- if (null != listFromContentProvider) {
- return listFromContentProvider;
+ // cacheDictionariesFromContentProvider returns the list of files it copied to local
+ // storage, but we don't really care about what was copied NOW: what we want is the
+ // list of everything we ever cached, so we ignore the return value.
+ BinaryDictionaryFileDumper.cacheDictionariesFromContentProvider(locale, context);
+ List<AssetFileAddress> cachedDictionaryList = getCachedDictionaryList(locale, context);
+ if (null != cachedDictionaryList) {
+ return cachedDictionaryList;
}
// If the list is null, fall through and return the fallback
} catch (FileNotFoundException e) {
diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java
index d779c8565..0640fd0b1 100644
--- a/java/src/com/android/inputmethod/latin/CandidateView.java
+++ b/java/src/com/android/inputmethod/latin/CandidateView.java
@@ -278,6 +278,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
private final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>();
+ public final boolean mAutoCorrectionVisualFlashEnabled;
public boolean mMoreSuggestionsAvailable;
public SuggestionsStripParams(Context context, AttributeSet attrs, int defStyle,
@@ -285,6 +286,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
super(words, dividers, infos);
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle);
+ mAutoCorrectionVisualFlashEnabled = a.getBoolean(
+ R.styleable.CandidateView_autoCorrectionVisualFlashEnabled, false);
mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0);
mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0);
mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0);
@@ -700,6 +703,9 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
}
public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) {
+ if (!mStripParams.mAutoCorrectionVisualFlashEnabled) {
+ return;
+ }
final CharSequence inverted = mStripParams.getInvertedText(autoCorrectedWord);
if (inverted == null)
return;
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index c28e40d95..a932f03ac 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -190,8 +190,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private long mLastKeyTime;
private AudioManager mAudioManager;
- // Align sound effect volume on music volume
- private static final float FX_VOLUME = -1.0f;
+ private static float mFxVolume = -1.0f; // just a default value to be updated runtime
private boolean mSilentModeOn; // System-wide current configuration
// TODO: Move this flag to VoiceProxy
@@ -510,6 +509,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
if (null == mSubtypeSwitcher) mSubtypeSwitcher = SubtypeSwitcher.getInstance();
mSettingsValues = new Settings.Values(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr());
resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
+ updateSoundEffectVolume();
}
private void initSuggest() {
@@ -2068,14 +2068,24 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
};
+ // update sound effect volume
+ private void updateSoundEffectVolume() {
+ if (mAudioManager == null) {
+ mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ if (mAudioManager == null) return;
+ }
+ // This aligns with the current media volume minus 6dB
+ mFxVolume = (float) mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
+ / (float) mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) / 4.0f;
+ }
+
// update flags for silent mode
private void updateRingerMode() {
if (mAudioManager == null) {
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ if (mAudioManager == null) return;
}
- if (mAudioManager != null) {
- mSilentModeOn = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
- }
+ mSilentModeOn = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
}
private void playKeyClick(int primaryCode) {
@@ -2087,8 +2097,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
}
if (isSoundOn()) {
- // FIXME: Volume and enable should come from UI settings
- // FIXME: These should be triggered after auto-repeat logic
int sound = AudioManager.FX_KEYPRESS_STANDARD;
switch (primaryCode) {
case Keyboard.CODE_DELETE:
@@ -2101,7 +2109,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
sound = AudioManager.FX_KEYPRESS_SPACEBAR;
break;
}
- mAudioManager.playSoundEffect(sound, FX_VOLUME);
+ mAudioManager.playSoundEffect(sound, mFxVolume);
}
}
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index f10b1b845..0a391a77e 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -318,7 +318,7 @@ public class SubtypeSwitcher {
// when the API level is 10 or previous.
mService.notifyOnCurrentInputMethodSubtypeChanged(subtype);
}
- }.execute();
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public Drawable getShortcutIcon() {
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 44e999572..d2b6bcdf2 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -126,7 +126,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
// Note : this must be reentrant
/**
* Gets a list of suggestions for a specific string. This returns a list of possible
- * corrections for the text passed as an arguments. It may split or group words, and
+ * corrections for the text passed as an argument. It may split or group words, and
* even perform grammatical analysis.
*/
@Override
@@ -153,9 +153,14 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
composer.add(character, proximities,
WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
}
- dictionary.getWords(composer, suggestionsGatherer, mProximityInfo);
- final boolean isInDict = dictionary.isValidWord(text);
- final String[] suggestions = suggestionsGatherer.getGatheredSuggestions();
+ final boolean isInDict;
+ final String[] suggestions;
+ synchronized(dictionary) {
+ // TODO: make the dictionary reentrant so that we don't have to synchronize here
+ dictionary.getWords(composer, suggestionsGatherer, mProximityInfo);
+ isInDict = dictionary.isValidWord(text);
+ suggestions = suggestionsGatherer.getGatheredSuggestions();
+ }
final int flags =
(isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY : 0)
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java
new file mode 100644
index 000000000..483679a55
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.android.inputmethod.latin.spellcheck;
+
+import com.android.inputmethod.latin.R;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+import java.util.List;
+
+/**
+ * Spell checker preference screen.
+ */
+public class SpellCheckerSettingsActivity extends PreferenceActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public Intent getIntent() {
+ final Intent modIntent = new Intent(super.getIntent());
+ modIntent.putExtra(EXTRA_SHOW_FRAGMENT, SpellCheckerSettingsFragment.class.getName());
+ modIntent.putExtra(EXTRA_NO_HEADERS, true);
+ return modIntent;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java
new file mode 100644
index 000000000..9b821be35
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.android.inputmethod.latin.spellcheck;
+
+import com.android.inputmethod.latin.R;
+
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+
+/**
+ * Preference screen.
+ */
+public class SpellCheckerSettingsFragment extends PreferenceFragment {
+ private static final String TAG = SpellCheckerSettingsFragment.class.getSimpleName();
+
+ /**
+ * Empty constructor for fragment generation.
+ */
+ public SpellCheckerSettingsFragment() {
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ addPreferencesFromResource(R.xml.spell_checker_settings);
+ }
+}