aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java173
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java12
-rw-r--r--java/src/com/android/inputmethod/latin/CandidateView.java9
-rw-r--r--java/src/com/android/inputmethod/latin/FileTransforms.java40
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java12
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeSwitcher.java35
-rw-r--r--java/src/com/android/inputmethod/latin/Utils.java28
7 files changed, 219 insertions, 90 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
index ed5f83b3b..24bb7b78a 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
@@ -63,10 +63,10 @@ public class BinaryDictionaryFileDumper {
}
/**
- * Queries a content provider for the list of dictionaries for a specific locale
+ * Queries a content provider for the list of word lists for a specific locale
* available to copy into Latin IME.
*/
- private static List<String> getDictIdList(final Locale locale, final Context context) {
+ private static List<String> getWordListIds(final Locale locale, final Context context) {
final ContentResolver resolver = context.getContentResolver();
final Uri dictionaryPackUri = getProviderUri(locale.toString());
@@ -87,77 +87,150 @@ public class BinaryDictionaryFileDumper {
return list;
}
+
/**
- * 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 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.
+ * Helper method to encapsulate exception handling.
*/
- public static List<AssetFileAddress> cacheDictionariesFromContentProvider(final Locale locale,
- final Context context) {
- 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 wordListUri = getProviderUri(id);
+ private static AssetFileDescriptor openAssetFileDescriptor(final ContentResolver resolver,
+ final Uri uri) {
+ try {
+ return resolver.openAssetFileDescriptor(uri, "r");
+ } catch (FileNotFoundException e) {
+ // I don't want to log the word list URI here for security concerns
+ Log.e(TAG, "Could not find a word list from the dictionary provider.");
+ return null;
+ }
+ }
+
+ /**
+ * Caches a word list the id of which is passed as an argument. This will write the file
+ * to the cache file name designated by its id and locale, overwriting it if already present
+ * and creating it (and its containing directory) if necessary.
+ */
+ private static AssetFileAddress cacheWordList(final String id, final Locale locale,
+ final ContentResolver resolver, final Context context) {
+
+ final int COMPRESSED_CRYPTED_COMPRESSED = 0;
+ final int CRYPTED_COMPRESSED = 1;
+ final int COMPRESSED_CRYPTED = 2;
+ final int COMPRESSED_ONLY = 3;
+ final int CRYPTED_ONLY = 4;
+ final int NONE = 5;
+ final int MODE_MIN = COMPRESSED_CRYPTED_COMPRESSED;
+ final int MODE_MAX = NONE;
+
+ final Uri wordListUri = getProviderUri(id);
+ final String outputFileName = BinaryDictionaryGetter.getCacheFileName(id, locale, context);
+
+ for (int mode = MODE_MIN; mode <= MODE_MAX; ++mode) {
+ InputStream originalSourceStream = null;
+ InputStream inputStream = null;
+ FileOutputStream outputStream = null;
AssetFileDescriptor afd = null;
try {
- afd = resolver.openAssetFileDescriptor(wordListUri, "r");
- } catch (FileNotFoundException e) {
- // leave null inside afd and continue
- }
- if (null == afd) continue;
- try {
- final String fileName = copyFileTo(afd.createInputStream(),
- BinaryDictionaryGetter.getCacheFileName(id, locale, context));
- afd.close();
+ // Open input.
+ afd = openAssetFileDescriptor(resolver, wordListUri);
+ // If we can't open it at all, don't even try a number of times.
+ if (null == afd) return null;
+ originalSourceStream = afd.createInputStream();
+ // Open output.
+ outputStream = new FileOutputStream(outputFileName);
+ // Get the appropriate decryption method for this try
+ switch (mode) {
+ case COMPRESSED_CRYPTED_COMPRESSED:
+ inputStream = FileTransforms.getUncompressedStream(
+ FileTransforms.getDecryptedStream(
+ FileTransforms.getUncompressedStream(
+ originalSourceStream)));
+ break;
+ case CRYPTED_COMPRESSED:
+ inputStream = FileTransforms.getUncompressedStream(
+ FileTransforms.getDecryptedStream(originalSourceStream));
+ break;
+ case COMPRESSED_CRYPTED:
+ inputStream = FileTransforms.getDecryptedStream(
+ FileTransforms.getUncompressedStream(originalSourceStream));
+ break;
+ case COMPRESSED_ONLY:
+ inputStream = FileTransforms.getUncompressedStream(originalSourceStream);
+ break;
+ case CRYPTED_ONLY:
+ inputStream = FileTransforms.getDecryptedStream(originalSourceStream);
+ break;
+ case NONE:
+ inputStream = originalSourceStream;
+ break;
+ }
+ copyFileTo(inputStream, outputStream);
if (0 >= resolver.delete(wordListUri, null, null)) {
- // I'd rather not print the word list ID to the log out of security concerns
Log.e(TAG, "Could not have the dictionary pack delete a word list");
}
- fileAddressList.add(AssetFileAddress.makeFromFileName(fileName));
- } catch (IOException e) {
- // Can't read the file for some reason. Continue onto the next file.
- Log.e(TAG, "Cannot read a word list from the dictionary pack : " + e);
+ // Success! Close files (through the finally{} clause) and return.
+ return AssetFileAddress.makeFromFileName(outputFileName);
+ } catch (Exception e) {
+ Log.e(TAG, "Can't open word list in mode " + mode + " : " + e);
+ // Try the next method.
+ } finally {
+ // Ignore exceptions while closing files.
+ try {
+ // afd.close() will close inputStream, we should not call inputStream.close().
+ if (null != afd) afd.close();
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while closing a cross-process file descriptor : " + e);
+ }
+ try {
+ if (null != outputStream) outputStream.close();
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while closing a file : " + e);
+ }
}
}
- return fileAddressList;
+
+ // We could not copy the file at all. This is very unexpected.
+ // I'd rather not print the word list ID to the log out of security concerns
+ Log.e(TAG, "Could not copy a word list. Will not be able to use it.");
+ // If we can't copy it we should probably delete it to avoid trying to copy it over
+ // and over each time we open LatinIME.
+ if (0 >= resolver.delete(wordListUri, null, null)) {
+ Log.e(TAG, "In addition, we were unable to delete it.");
+ }
+ return null;
}
/**
- * Accepts a resource number as dictionary data for some locale and returns the name of a file.
+ * Queries a content provider for word list data for some locale and cache the returned files
*
- * This will make the resource the cached dictionary for this locale, overwriting any previous
- * cached data.
+ * This will query a content provider for word list data for a given locale, and copy the
+ * files locally so that they can be mmap'ed. This may overwrite previously cached word lists
+ * with newer versions if a newer version is made available by the content provider.
+ * @returns the addresses of the word list 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 String getDictionaryFileFromResource(int resource, Locale locale,
- Context context) throws FileNotFoundException, IOException {
- final Resources res = context.getResources();
- final Locale savedLocale = Utils.setSystemLocale(res, locale);
- final InputStream stream = res.openRawResource(resource);
- Utils.setSystemLocale(res, savedLocale);
- return copyFileTo(stream,
- BinaryDictionaryGetter.getCacheFileName(Integer.toString(resource),
- locale, context));
+ public static List<AssetFileAddress> cacheWordListsFromContentProvider(final Locale locale,
+ final Context context) {
+ final ContentResolver resolver = context.getContentResolver();
+ final List<String> idList = getWordListIds(locale, context);
+ final List<AssetFileAddress> fileAddressList = new ArrayList<AssetFileAddress>();
+ for (String id : idList) {
+ final AssetFileAddress afd = cacheWordList(id, locale, resolver, context);
+ if (null != afd) {
+ fileAddressList.add(afd);
+ }
+ }
+ return fileAddressList;
}
/**
- * Copies the data in an input stream to a target file, creating the file if necessary and
- * overwriting it if it already exists.
+ * Copies the data in an input stream to a target file.
* @param input the stream to be copied.
- * @param outputFileName the name of a file to copy the data to. It is created if necessary.
+ * @param outputFile an outputstream to copy the data to.
*/
- private static String copyFileTo(final InputStream input, final String outputFileName)
+ private static void copyFileTo(final InputStream input, final FileOutputStream output)
throws FileNotFoundException, IOException {
final byte[] buffer = new byte[FILE_READ_BUFFER_SIZE];
- final FileOutputStream output = new FileOutputStream(outputFileName);
for (int readBytes = input.read(buffer); readBytes >= 0; readBytes = input.read(buffer))
output.write(buffer, 0, readBytes);
input.close();
- return outputFileName;
}
}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 5d2dab0a9..38344300c 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -205,7 +205,7 @@ class BinaryDictionaryGetter {
* @param context the context on which to open the files upon.
* @return an array of binary dictionary files, which may be empty but may not be null.
*/
- private static File[] getCachedDictionaryList(final Locale locale,
+ private static File[] getCachedWordLists(final Locale locale,
final Context context) {
final String directoryName = getCacheDirectoryForLocale(locale, context);
final File[] cacheFiles = new File(directoryName).listFiles();
@@ -235,11 +235,11 @@ class BinaryDictionaryGetter {
public static List<AssetFileAddress> getDictionaryFiles(final Locale locale,
final Context context, final int fallbackResId) {
- // cacheDictionariesFromContentProvider returns the list of files it copied to local
+ // cacheWordListsFromContentProvider 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);
- final File[] cachedDictionaryList = getCachedDictionaryList(locale, context);
+ BinaryDictionaryFileDumper.cacheWordListsFromContentProvider(locale, context);
+ final File[] cachedWordLists = getCachedWordLists(locale, context);
final String mainDictId = getMainDictId(locale);
@@ -247,8 +247,8 @@ class BinaryDictionaryGetter {
boolean foundMainDict = false;
final ArrayList<AssetFileAddress> fileList = new ArrayList<AssetFileAddress>();
- // cachedDictionaryList may not be null, see doc for getCachedDictionaryList
- for (final File f : cachedDictionaryList) {
+ // cachedWordLists may not be null, see doc for getCachedDictionaryList
+ for (final File f : cachedWordLists) {
final String wordListId = getWordListIdFromFileName(f.getName());
if (wordListId.equals(mainDictId)) {
foundMainDict = true;
diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java
index d46b4b5b5..5f20c70b4 100644
--- a/java/src/com/android/inputmethod/latin/CandidateView.java
+++ b/java/src/com/android/inputmethod/latin/CandidateView.java
@@ -413,8 +413,10 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
// TODO: This "more suggestions hint" should have nicely designed icon.
word.setCompoundDrawablesWithIntrinsicBounds(
null, null, null, mMoreCandidateHint);
+ // HACK: To align with other TextView that has no compound drawables.
+ word.setCompoundDrawablePadding(-mMoreCandidateHint.getIntrinsicHeight());
} else {
- word.setCompoundDrawables(null, null, null, null);
+ word.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
}
// Disable this candidate if the suggestion is null or empty.
@@ -426,7 +428,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
word.setText(text); // TextView.setText() resets text scale x to 1.0.
word.setTextScaleX(scaleX);
stripView.addView(word);
- setLayoutWeight(word, getCandidateWeight(index), mCandidateStripHeight);
+ setLayoutWeight(word, getCandidateWeight(index), MATCH_PARENT);
if (DBG) {
final CharSequence debugInfo = getDebugInfo(suggestions, pos);
@@ -526,8 +528,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
mPreviewPopup = new PopupWindow(context);
mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null);
- mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
+ mPreviewPopup.setWindowLayoutMode(WRAP_CONTENT, WRAP_CONTENT);
mPreviewPopup.setContentView(mPreviewText);
mPreviewPopup.setBackgroundDrawable(null);
diff --git a/java/src/com/android/inputmethod/latin/FileTransforms.java b/java/src/com/android/inputmethod/latin/FileTransforms.java
new file mode 100644
index 000000000..d0374e01e
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/FileTransforms.java
@@ -0,0 +1,40 @@
+/*
+ * 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.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.GZIPInputStream;
+
+public class FileTransforms {
+ public static OutputStream getCryptedStream(OutputStream out) {
+ // Crypt the stream.
+ return out;
+ }
+
+ public static InputStream getDecryptedStream(InputStream in) {
+ // Decrypt the stream.
+ return in;
+ }
+
+ public static InputStream getUncompressedStream(InputStream in) throws IOException {
+ return new GZIPInputStream(in);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 394414d03..552517bc8 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -106,6 +106,18 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
*/
public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey";
+ /**
+ * The private IME option used to indicate that the given text field needs
+ * ASCII code points input.
+ */
+ public static final String IME_OPTION_FORCE_ASCII = "forceAscii";
+
+ /**
+ * The subtype extra value used to indicate that the subtype keyboard layout is capable for
+ * typing ASCII characters.
+ */
+ public static final String SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
+
private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
// How many continuous deletes at which to start deleting at a higher speed.
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index 0a391a77e..d969e39eb 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -415,7 +415,10 @@ public class SubtypeSwitcher {
return mEnabledKeyboardSubtypesOfCurrentInputMethod.size();
}
- public boolean needsToDisplayLanguage() {
+ public boolean needsToDisplayLanguage(Locale keyboardLocale) {
+ if (!keyboardLocale.equals(mInputLocale)) {
+ return false;
+ }
return mNeedsToDisplayLanguage;
}
@@ -492,36 +495,8 @@ public class SubtypeSwitcher {
KeyboardSwitcher.getInstance().getKeyboardView().getWindowToken());
}
- public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) {
- if (returnsNameInThisLocale) {
- return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale);
- } else {
- return toTitleCase(locale.getDisplayName(), locale);
- }
- }
-
- public static String getDisplayLanguage(Locale locale) {
- return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale);
- }
-
- public static String getMiddleDisplayLanguage(Locale locale) {
- return toTitleCase((Utils.constructLocaleFromString(
- locale.getLanguage()).getDisplayLanguage(locale)), locale);
- }
-
- public static String getShortDisplayLanguage(Locale locale) {
- return toTitleCase(locale.getLanguage(), locale);
- }
-
- private static String toTitleCase(String s, Locale locale) {
- if (s.length() == 0) {
- return s;
- }
- return s.toUpperCase(locale).charAt(0) + s.substring(1);
- }
-
public String getInputLanguageName() {
- return getDisplayLanguage(getInputLocale());
+ return Utils.getDisplayLanguage(getInputLocale());
}
/////////////////////////////
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 36fbfd951..ff051dcbb 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -769,4 +769,32 @@ public class Utils {
StringBuilderPool.recycle((StringBuilder)garbage);
}
}
+
+ public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) {
+ if (returnsNameInThisLocale) {
+ return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale);
+ } else {
+ return toTitleCase(locale.getDisplayName(), locale);
+ }
+ }
+
+ public static String getDisplayLanguage(Locale locale) {
+ return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale);
+ }
+
+ public static String getMiddleDisplayLanguage(Locale locale) {
+ return toTitleCase((constructLocaleFromString(
+ locale.getLanguage()).getDisplayLanguage(locale)), locale);
+ }
+
+ public static String getShortDisplayLanguage(Locale locale) {
+ return toTitleCase(locale.getLanguage(), locale);
+ }
+
+ private static String toTitleCase(String s, Locale locale) {
+ if (s.length() <= 1) {
+ return s;
+ }
+ return s.toUpperCase(locale).charAt(0) + s.substring(1);
+ }
}