Merge "Add different ways of reading the dictionary file."
commit
0a7cf81ca2
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* 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 java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immutable class to hold the address of an asset.
|
||||||
|
* As opposed to a normal file, an asset is usually represented as a contiguous byte array in
|
||||||
|
* the package file. Open it correctly thus requires the name of the package it is in, but
|
||||||
|
* also the offset in the file and the length of this data. This class encapsulates these three.
|
||||||
|
*/
|
||||||
|
class AssetFileAddress {
|
||||||
|
public final String mFilename;
|
||||||
|
public final long mOffset;
|
||||||
|
public final long mLength;
|
||||||
|
|
||||||
|
public AssetFileAddress(final String filename, final long offset, final long length) {
|
||||||
|
mFilename = filename;
|
||||||
|
mOffset = offset;
|
||||||
|
mLength = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AssetFileAddress makeFromFileName(final String filename) {
|
||||||
|
if (null == filename) return null;
|
||||||
|
File f = new File(filename);
|
||||||
|
if (null == f || !f.isFile()) return null;
|
||||||
|
return new AssetFileAddress(filename, 0l, f.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AssetFileAddress makeFromFileNameAndOffset(final String filename,
|
||||||
|
final long offset, final long length) {
|
||||||
|
if (null == filename) return null;
|
||||||
|
File f = new File(filename);
|
||||||
|
if (null == f || !f.isFile()) return null;
|
||||||
|
return new AssetFileAddress(filename, offset, length);
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,14 +26,18 @@ import android.util.Log;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements a static, compacted, binary dictionary of standard words.
|
* Implements a static, compacted, binary dictionary of standard words.
|
||||||
*/
|
*/
|
||||||
public class BinaryDictionary extends Dictionary {
|
public class BinaryDictionary extends Dictionary {
|
||||||
|
|
||||||
|
public static final String DICTIONARY_PACK_AUTHORITY =
|
||||||
|
"com.android.inputmethod.latin.dictionarypack";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There is difference between what java and native code can handle.
|
* There is a difference between what java and native code can handle.
|
||||||
* This value should only be used in BinaryDictionary.java
|
* This value should only be used in BinaryDictionary.java
|
||||||
* It is necessary to keep it at this value because some languages e.g. German have
|
* It is necessary to keep it at this value because some languages e.g. German have
|
||||||
* really long words.
|
* really long words.
|
||||||
|
@ -85,10 +89,11 @@ public class BinaryDictionary extends Dictionary {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize a dictionary from a raw resource file
|
* Initializes a dictionary from a raw resource file
|
||||||
* @param context application context for reading resources
|
* @param context application context for reading resources
|
||||||
* @param resId the resource containing the raw binary dictionary
|
* @param resId the resource containing the raw binary dictionary
|
||||||
* @return initialized instance of BinaryDictionary
|
* @param dicTypeId the type of the dictionary being created, out of the list in Suggest.DIC_*
|
||||||
|
* @return an initialized instance of BinaryDictionary
|
||||||
*/
|
*/
|
||||||
public static BinaryDictionary initDictionary(Context context, int resId, int dicTypeId) {
|
public static BinaryDictionary initDictionary(Context context, int resId, int dicTypeId) {
|
||||||
synchronized (sInstance) {
|
synchronized (sInstance) {
|
||||||
|
@ -146,6 +151,37 @@ public class BinaryDictionary extends Dictionary {
|
||||||
Utils.loadNativeLibrary();
|
Utils.loadNativeLibrary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a dictionary from a dictionary pack.
|
||||||
|
*
|
||||||
|
* This searches for a content provider providing a dictionary pack for the specified
|
||||||
|
* locale. If none is found, it falls back to using the resource passed as fallBackResId
|
||||||
|
* as a dictionary.
|
||||||
|
* @param context application context for reading resources
|
||||||
|
* @param dicTypeId the type of the dictionary being created, out of the list in Suggest.DIC_*
|
||||||
|
* @param locale the locale for which to create the dictionary
|
||||||
|
* @param fallBackResId the id of the resource to use as a fallback if no pack is found
|
||||||
|
* @return an initialized instance of BinaryDictionary
|
||||||
|
*/
|
||||||
|
public static BinaryDictionary initDictionaryFromManager(Context context, int dicTypeId,
|
||||||
|
Locale locale, int fallbackResId) {
|
||||||
|
if (null == locale) {
|
||||||
|
Log.e(TAG, "No locale defined for dictionary");
|
||||||
|
return initDictionary(context, fallbackResId, dicTypeId);
|
||||||
|
}
|
||||||
|
synchronized (sInstance) {
|
||||||
|
sInstance.closeInternal();
|
||||||
|
|
||||||
|
final AssetFileAddress dictFile = BinaryDictionaryGetter.getDictionaryFile(locale,
|
||||||
|
context, fallbackResId);
|
||||||
|
if (null != dictFile) {
|
||||||
|
sInstance.loadDictionary(dictFile.mFilename, dictFile.mOffset, dictFile.mLength);
|
||||||
|
sInstance.mDicTypeId = dicTypeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
private native int openNative(String sourceDir, long dictOffset, long dictSize,
|
private native int openNative(String sourceDir, long dictOffset, long dictSize,
|
||||||
int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength,
|
int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength,
|
||||||
int maxWords, int maxAlternatives);
|
int maxWords, int maxAlternatives);
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* 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.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Group class for static methods to help with creation and getting of the binary dictionary
|
||||||
|
* file from the dictionary provider
|
||||||
|
*/
|
||||||
|
public class BinaryDictionaryFileDumper {
|
||||||
|
/**
|
||||||
|
* The size of the temporary buffer to copy files.
|
||||||
|
*/
|
||||||
|
static final int FILE_READ_BUFFER_SIZE = 1024;
|
||||||
|
|
||||||
|
// Prevents this class to be accidentally instantiated.
|
||||||
|
private BinaryDictionaryFileDumper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a file name that matches the locale passed as an argument.
|
||||||
|
* The file name is basically the result of the .toString() method, except we replace
|
||||||
|
* any @File.separator with an underscore to avoid generating a file name that may not
|
||||||
|
* be created.
|
||||||
|
* @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 getCacheFileNameForLocale(Locale locale, Context context) {
|
||||||
|
// The following assumes two things :
|
||||||
|
// 1. That File.separator is not the same character as "_"
|
||||||
|
// I don't think any android system will ever use "_" as a path separator
|
||||||
|
// 2. That no two locales differ by only a File.separator versus a "_"
|
||||||
|
// Since "_" can't be part of locale components this should be safe.
|
||||||
|
// Examples:
|
||||||
|
// en -> en
|
||||||
|
// en_US_POSIX -> en_US_POSIX
|
||||||
|
// en__foo/bar -> en__foo_bar
|
||||||
|
final String[] separator = { File.separator };
|
||||||
|
final String[] empty = { "_" };
|
||||||
|
final CharSequence basename = TextUtils.replace(locale.toString(), separator, empty);
|
||||||
|
return context.getFilesDir() + File.separator + basename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return for a given locale the provider URI to query to get the dictionary.
|
||||||
|
*/
|
||||||
|
public static Uri getProviderUri(Locale locale) {
|
||||||
|
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(BinaryDictionary.DICTIONARY_PACK_AUTHORITY).appendPath(
|
||||||
|
locale.toString()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries a content provider for dictionary data for some locale and returns it as a file name.
|
||||||
|
*
|
||||||
|
* This will query a content provider for dictionary data for a given locale, and return
|
||||||
|
* the name of a file suitable to be mmap'ed. It will copy it to local storage if needed.
|
||||||
|
* It should also check the dictionary version 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.
|
||||||
|
* @returns the name of the file, 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 getDictionaryFileFromContentProvider(Locale locale, Context context)
|
||||||
|
throws FileNotFoundException, IOException {
|
||||||
|
// TODO: check whether the dictionary is the same or not and if it is, return the cached
|
||||||
|
// file.
|
||||||
|
final ContentResolver resolver = context.getContentResolver();
|
||||||
|
final Uri dictionaryPackUri = getProviderUri(locale);
|
||||||
|
final InputStream stream = resolver.openInputStream(dictionaryPackUri);
|
||||||
|
if (null == stream) return null;
|
||||||
|
return copyFileTo(stream, getCacheFileNameForLocale(locale, context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts a file as dictionary data for some locale and returns the name of a file.
|
||||||
|
*
|
||||||
|
* This will make the data in the input file the cached dictionary for this locale, overwriting
|
||||||
|
* any previous cached data.
|
||||||
|
*/
|
||||||
|
public static String getDictionaryFileFromFile(String fileName, Locale locale,
|
||||||
|
Context context) throws FileNotFoundException, IOException {
|
||||||
|
return copyFileTo(new FileInputStream(fileName), getCacheFileNameForLocale(locale,
|
||||||
|
context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts a resource number as dictionary data for some locale and returns the name of a file.
|
||||||
|
*
|
||||||
|
* This will make the resource the cached dictionary for this locale, overwriting any previous
|
||||||
|
* cached data.
|
||||||
|
*/
|
||||||
|
public static String getDictionaryFileFromResource(int resource, Locale locale,
|
||||||
|
Context context) throws FileNotFoundException, IOException {
|
||||||
|
return copyFileTo(context.getResources().openRawResource(resource),
|
||||||
|
getCacheFileNameForLocale(locale, context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the data in an input stream to a target file, creating the file if necessary and
|
||||||
|
* overwriting it if it already exists.
|
||||||
|
*/
|
||||||
|
private static String copyFileTo(final InputStream input, final String outputFileName)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* 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.AssetFileDescriptor;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to get the address of a mmap'able dictionary file.
|
||||||
|
*/
|
||||||
|
class BinaryDictionaryGetter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for Log actions from this class
|
||||||
|
*/
|
||||||
|
private static final String TAG = BinaryDictionaryGetter.class.getSimpleName();
|
||||||
|
|
||||||
|
// Prevents this from being instantiated
|
||||||
|
private BinaryDictionaryGetter() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a file address from a resource, or null if it cannot be opened.
|
||||||
|
*/
|
||||||
|
private static AssetFileAddress loadFallbackResource(Context context, int fallbackResId) {
|
||||||
|
final AssetFileDescriptor afd = context.getResources().openRawResourceFd(fallbackResId);
|
||||||
|
if (afd == null) {
|
||||||
|
Log.e(TAG, "Found the resource but cannot read it. Is it compressed? resId="
|
||||||
|
+ fallbackResId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return AssetFileAddress.makeFromFileNameAndOffset(
|
||||||
|
context.getApplicationInfo().sourceDir, afd.getStartOffset(), afd.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a file address for a given locale, trying relevant methods in order.
|
||||||
|
*
|
||||||
|
* Tries to get a binary dictionary from various sources, in order:
|
||||||
|
* - Uses a private method of getting a private dictionary, as implemented by the
|
||||||
|
* PrivateBinaryDictionaryGetter class.
|
||||||
|
* If that fails:
|
||||||
|
* - Uses a content provider to get a public dictionary, as per the protocol described
|
||||||
|
* in BinaryDictionaryFileDumper.
|
||||||
|
* If that fails:
|
||||||
|
* - Gets a file name from the fallback resource passed as an argument.
|
||||||
|
* If that fails:
|
||||||
|
* - Returns null.
|
||||||
|
* @return The address of a valid file, or null.
|
||||||
|
* @throws FileNotFoundException if a dictionary provider returned a file name, but the
|
||||||
|
* file cannot be found.
|
||||||
|
* @throws IOException if there was an I/O problem reading or copying a file.
|
||||||
|
*/
|
||||||
|
public static AssetFileAddress getDictionaryFile(Locale locale, Context context,
|
||||||
|
int fallbackResId) {
|
||||||
|
// Try first to query a private file signed the same way.
|
||||||
|
final AssetFileAddress privateFile =
|
||||||
|
PrivateBinaryDictionaryGetter.getDictionaryFile(locale, context);
|
||||||
|
if (null != privateFile) {
|
||||||
|
return privateFile;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
// If that was no-go, try to find a publicly exported dictionary.
|
||||||
|
final String fileName = BinaryDictionaryFileDumper.
|
||||||
|
getDictionaryFileFromContentProvider(locale, context);
|
||||||
|
return AssetFileAddress.makeFromFileName(fileName);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.e(TAG, "Unable to create dictionary file from provider for locale "
|
||||||
|
+ locale.toString() + ": falling back to internal dictionary");
|
||||||
|
return loadFallbackResource(context, fallbackResId);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Unable to read source data for locale "
|
||||||
|
+ locale.toString() + ": falling back to internal dictionary");
|
||||||
|
return loadFallbackResource(context, fallbackResId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* 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.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.ProviderInfo;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes action to reload the necessary data when a dictionary pack was added/removed.
|
||||||
|
*/
|
||||||
|
public class DictionaryPackInstallBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
final LatinIME mService;
|
||||||
|
|
||||||
|
public DictionaryPackInstallBroadcastReceiver(final LatinIME service) {
|
||||||
|
mService = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
final String action = intent.getAction();
|
||||||
|
final PackageManager manager = context.getPackageManager();
|
||||||
|
|
||||||
|
// We need to reread the dictionary if a new dictionary package is installed.
|
||||||
|
if (action.equals(Intent.ACTION_PACKAGE_ADDED)) {
|
||||||
|
final Uri packageUri = intent.getData();
|
||||||
|
if (null == packageUri) return; // No package name : we can't do anything
|
||||||
|
final String packageName = packageUri.getSchemeSpecificPart();
|
||||||
|
if (null == packageName) return;
|
||||||
|
final PackageInfo packageInfo;
|
||||||
|
try {
|
||||||
|
packageInfo = manager.getPackageInfo(packageName, PackageManager.GET_PROVIDERS);
|
||||||
|
} catch (android.content.pm.PackageManager.NameNotFoundException e) {
|
||||||
|
return; // No package info : we can't do anything
|
||||||
|
}
|
||||||
|
final ProviderInfo[] providers = packageInfo.providers;
|
||||||
|
if (null == providers) return; // No providers : it is not a dictionary.
|
||||||
|
|
||||||
|
// Search for some dictionary pack in the just-installed package. If found, reread.
|
||||||
|
boolean found = false;
|
||||||
|
for (ProviderInfo info : providers) {
|
||||||
|
if (BinaryDictionary.DICTIONARY_PACK_AUTHORITY.equals(info.authority)) {
|
||||||
|
mService.resetSuggestMainDict();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we come here none of the authorities matched the one we searched for.
|
||||||
|
// We can exit safely.
|
||||||
|
return;
|
||||||
|
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
|
||||||
|
&& !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
|
||||||
|
// When the dictionary package is removed, we need to reread dictionary (to use the
|
||||||
|
// next-priority one, or stop using a dictionary at all if this was the only one,
|
||||||
|
// since this is the user request).
|
||||||
|
// If we are replacing the package, we will receive ADDED right away so no need to
|
||||||
|
// remove the dictionary at the moment, since we will do it when we receive the
|
||||||
|
// ADDED broadcast.
|
||||||
|
|
||||||
|
// TODO: Only reload dictionary on REMOVED when the removed package is the one we
|
||||||
|
// read dictionary from?
|
||||||
|
mService.resetSuggestMainDict();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -106,8 +106,8 @@ public class InputLanguageSelection extends PreferenceActivity {
|
||||||
conf.locale = locale;
|
conf.locale = locale;
|
||||||
res.updateConfiguration(conf, res.getDisplayMetrics());
|
res.updateConfiguration(conf, res.getDisplayMetrics());
|
||||||
|
|
||||||
int mainDicResId = Utils.getMainDictionaryResourceId(res);
|
BinaryDictionary bd = BinaryDictionary.initDictionaryFromManager(this, Suggest.DIC_MAIN,
|
||||||
BinaryDictionary bd = BinaryDictionary.initDictionary(this, mainDicResId, Suggest.DIC_MAIN);
|
locale, Utils.getMainDictionaryResourceId(res));
|
||||||
|
|
||||||
// Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of
|
// Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of
|
||||||
// 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words.
|
// 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words.
|
||||||
|
|
|
@ -120,6 +120,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
// Key events coming any faster than this are long-presses.
|
// Key events coming any faster than this are long-presses.
|
||||||
private static final int QUICK_PRESS = 200;
|
private static final int QUICK_PRESS = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the scheme used by the Package Manager to warn of a new package installation,
|
||||||
|
* replacement or removal.
|
||||||
|
*/
|
||||||
|
private static final String SCHEME_PACKAGE = "package";
|
||||||
|
|
||||||
private int mSuggestionVisibility;
|
private int mSuggestionVisibility;
|
||||||
private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
|
private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
|
||||||
= R.string.prefs_suggestion_visibility_show_value;
|
= R.string.prefs_suggestion_visibility_show_value;
|
||||||
|
@ -208,6 +214,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
// TODO: Move this flag to VoiceIMEConnector
|
// TODO: Move this flag to VoiceIMEConnector
|
||||||
private boolean mConfigurationChanging;
|
private boolean mConfigurationChanging;
|
||||||
|
|
||||||
|
// Object for reacting to adding/removing a dictionary pack.
|
||||||
|
private BroadcastReceiver mDictionaryPackInstallReceiver =
|
||||||
|
new DictionaryPackInstallBroadcastReceiver(this);
|
||||||
|
|
||||||
// Keeps track of most recently inserted text (multi-character key) for reverting
|
// Keeps track of most recently inserted text (multi-character key) for reverting
|
||||||
private CharSequence mEnteredText;
|
private CharSequence mEnteredText;
|
||||||
|
|
||||||
|
@ -415,18 +425,26 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
mOrientation = res.getConfiguration().orientation;
|
mOrientation = res.getConfiguration().orientation;
|
||||||
initSuggestPuncList();
|
initSuggestPuncList();
|
||||||
|
|
||||||
// register to receive ringer mode change and network state change.
|
// Register to receive ringer mode change and network state change.
|
||||||
|
// Also receive installation and removal of a dictionary pack.
|
||||||
final IntentFilter filter = new IntentFilter();
|
final IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
|
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
|
||||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
registerReceiver(mReceiver, filter);
|
registerReceiver(mReceiver, filter);
|
||||||
mVoiceConnector = VoiceConnector.init(this, prefs, mHandler);
|
mVoiceConnector = VoiceConnector.init(this, prefs, mHandler);
|
||||||
|
|
||||||
|
final IntentFilter packageFilter = new IntentFilter();
|
||||||
|
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
|
||||||
|
packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
|
||||||
|
packageFilter.addDataScheme(SCHEME_PACKAGE);
|
||||||
|
registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initSuggest() {
|
private void initSuggest() {
|
||||||
String locale = mSubtypeSwitcher.getInputLocaleStr();
|
final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
|
||||||
|
final Locale keyboardLocale = new Locale(localeStr);
|
||||||
|
|
||||||
Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(new Locale(locale));
|
final Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(keyboardLocale);
|
||||||
if (mSuggest != null) {
|
if (mSuggest != null) {
|
||||||
mSuggest.close();
|
mSuggest.close();
|
||||||
}
|
}
|
||||||
|
@ -435,20 +453,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
|
|
||||||
final Resources res = mResources;
|
final Resources res = mResources;
|
||||||
int mainDicResId = Utils.getMainDictionaryResourceId(res);
|
int mainDicResId = Utils.getMainDictionaryResourceId(res);
|
||||||
mSuggest = new Suggest(this, mainDicResId);
|
mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
|
||||||
loadAndSetAutoCorrectionThreshold(prefs);
|
loadAndSetAutoCorrectionThreshold(prefs);
|
||||||
updateAutoTextEnabled();
|
updateAutoTextEnabled();
|
||||||
|
|
||||||
mUserDictionary = new UserDictionary(this, locale);
|
mUserDictionary = new UserDictionary(this, localeStr);
|
||||||
mSuggest.setUserDictionary(mUserDictionary);
|
mSuggest.setUserDictionary(mUserDictionary);
|
||||||
|
|
||||||
mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
|
mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
|
||||||
mSuggest.setContactsDictionary(mContactsDictionary);
|
mSuggest.setContactsDictionary(mContactsDictionary);
|
||||||
|
|
||||||
mAutoDictionary = new AutoDictionary(this, this, locale, Suggest.DIC_AUTO);
|
mAutoDictionary = new AutoDictionary(this, this, localeStr, Suggest.DIC_AUTO);
|
||||||
mSuggest.setAutoDictionary(mAutoDictionary);
|
mSuggest.setAutoDictionary(mAutoDictionary);
|
||||||
|
|
||||||
mUserBigramDictionary = new UserBigramDictionary(this, this, locale, Suggest.DIC_USER);
|
mUserBigramDictionary = new UserBigramDictionary(this, this, localeStr, Suggest.DIC_USER);
|
||||||
mSuggest.setUserBigramDictionary(mUserBigramDictionary);
|
mSuggest.setUserBigramDictionary(mUserBigramDictionary);
|
||||||
|
|
||||||
updateCorrectionMode();
|
updateCorrectionMode();
|
||||||
|
@ -458,6 +476,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
mSubtypeSwitcher.changeSystemLocale(savedLocale);
|
mSubtypeSwitcher.changeSystemLocale(savedLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* package private */ void resetSuggestMainDict() {
|
||||||
|
final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
|
||||||
|
final Locale keyboardLocale = new Locale(localeStr);
|
||||||
|
int mainDicResId = Utils.getMainDictionaryResourceId(mResources);
|
||||||
|
mSuggest.resetMainDict(this, mainDicResId, keyboardLocale);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
if (mSuggest != null) {
|
if (mSuggest != null) {
|
||||||
|
@ -465,6 +490,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
mSuggest = null;
|
mSuggest = null;
|
||||||
}
|
}
|
||||||
unregisterReceiver(mReceiver);
|
unregisterReceiver(mReceiver);
|
||||||
|
unregisterReceiver(mDictionaryPackInstallReceiver);
|
||||||
mVoiceConnector.destroy();
|
mVoiceConnector.destroy();
|
||||||
LatinImeLogger.commit();
|
LatinImeLogger.commit();
|
||||||
LatinImeLogger.onDestroy();
|
LatinImeLogger.onDestroy();
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* 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 java.util.Locale;
|
||||||
|
|
||||||
|
class PrivateBinaryDictionaryGetter {
|
||||||
|
private PrivateBinaryDictionaryGetter() {}
|
||||||
|
public static AssetFileAddress getDictionaryFile(Locale locale, Context context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -106,8 +107,9 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
|
|
||||||
private int mCorrectionMode = CORRECTION_BASIC;
|
private int mCorrectionMode = CORRECTION_BASIC;
|
||||||
|
|
||||||
public Suggest(Context context, int dictionaryResId) {
|
public Suggest(Context context, int dictionaryResId, Locale locale) {
|
||||||
init(context, BinaryDictionary.initDictionary(context, dictionaryResId, DIC_MAIN));
|
init(context, BinaryDictionary.initDictionaryFromManager(context, DIC_MAIN, locale,
|
||||||
|
dictionaryResId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package for test */ Suggest(File dictionary, long startOffset, long length,
|
/* package for test */ Suggest(File dictionary, long startOffset, long length,
|
||||||
|
@ -130,6 +132,19 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
initPool();
|
initPool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void resetMainDict(Context context, int dictionaryResId, Locale locale) {
|
||||||
|
final BinaryDictionary newMainDict = BinaryDictionary.initDictionaryFromManager(context,
|
||||||
|
DIC_MAIN, locale, dictionaryResId);
|
||||||
|
mMainDict = newMainDict;
|
||||||
|
if (null == newMainDict) {
|
||||||
|
mUnigramDictionaries.remove(DICT_KEY_MAIN);
|
||||||
|
mBigramDictionaries.remove(DICT_KEY_MAIN);
|
||||||
|
} else {
|
||||||
|
mUnigramDictionaries.put(DICT_KEY_MAIN, newMainDict);
|
||||||
|
mBigramDictionaries.put(DICT_KEY_MAIN, newMainDict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initPool() {
|
private void initPool() {
|
||||||
for (int i = 0; i < mPrefMaxSuggestions; i++) {
|
for (int i = 0; i < mPrefMaxSuggestions; i++) {
|
||||||
StringBuilder sb = new StringBuilder(getApproxMaxWordLength());
|
StringBuilder sb = new StringBuilder(getApproxMaxWordLength());
|
||||||
|
|
|
@ -551,7 +551,9 @@ public class Utils {
|
||||||
* @return main dictionary resource id
|
* @return main dictionary resource id
|
||||||
*/
|
*/
|
||||||
public static int getMainDictionaryResourceId(Resources res) {
|
public static int getMainDictionaryResourceId(Resources res) {
|
||||||
return res.getIdentifier("main", "raw", LatinIME.class.getPackage().getName());
|
final String MAIN_DIC_NAME = "main";
|
||||||
|
String packageName = LatinIME.class.getPackage().getName();
|
||||||
|
return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void loadNativeLibrary() {
|
public static void loadNativeLibrary() {
|
||||||
|
|
|
@ -34,7 +34,9 @@ public class SuggestHelper {
|
||||||
private final KeyDetector mKeyDetector;
|
private final KeyDetector mKeyDetector;
|
||||||
|
|
||||||
public SuggestHelper(Context context, int dictionaryId, KeyboardId keyboardId) {
|
public SuggestHelper(Context context, int dictionaryId, KeyboardId keyboardId) {
|
||||||
mSuggest = new Suggest(context, dictionaryId);
|
// Use null as the locale for Suggest so as to force it to use the internal dictionary
|
||||||
|
// (and not try to find a dictionary provider for a specified locale)
|
||||||
|
mSuggest = new Suggest(context, dictionaryId, null);
|
||||||
mKeyboard = new LatinKeyboard(context, keyboardId);
|
mKeyboard = new LatinKeyboard(context, keyboardId);
|
||||||
mKeyDetector = new ProximityKeyDetector();
|
mKeyDetector = new ProximityKeyDetector();
|
||||||
init();
|
init();
|
||||||
|
|
Loading…
Reference in New Issue