diff options
Diffstat (limited to 'java/src')
8 files changed, 226 insertions, 75 deletions
diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java index 1511dbcfe..dac12137d 100644 --- a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java +++ b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java @@ -36,8 +36,6 @@ import java.util.TreeMap; * Various helper functions for the state database */ public class MetadataDbHelper extends SQLiteOpenHelper { - - @SuppressWarnings("unused") private static final String TAG = MetadataDbHelper.class.getSimpleName(); // This was the initial release version of the database. It should never be @@ -437,37 +435,37 @@ public class MetadataDbHelper extends SQLiteOpenHelper { */ public static ContentValues completeWithDefaultValues(final ContentValues result) throws BadFormatException { - if (!result.containsKey(WORDLISTID_COLUMN) || !result.containsKey(LOCALE_COLUMN)) { + if (null == result.get(WORDLISTID_COLUMN) || null == result.get(LOCALE_COLUMN)) { throw new BadFormatException(); } // 0 for the pending id, because there is none - if (!result.containsKey(PENDINGID_COLUMN)) result.put(PENDINGID_COLUMN, 0); + if (null == result.get(PENDINGID_COLUMN)) result.put(PENDINGID_COLUMN, 0); // This is a binary blob of a dictionary - if (!result.containsKey(TYPE_COLUMN)) result.put(TYPE_COLUMN, TYPE_BULK); + if (null == result.get(TYPE_COLUMN)) result.put(TYPE_COLUMN, TYPE_BULK); // This word list is unknown, but it's present, else we wouldn't be here, so INSTALLED - if (!result.containsKey(STATUS_COLUMN)) result.put(STATUS_COLUMN, STATUS_INSTALLED); + if (null == result.get(STATUS_COLUMN)) result.put(STATUS_COLUMN, STATUS_INSTALLED); // No description unless specified, because we can't guess it - if (!result.containsKey(DESCRIPTION_COLUMN)) result.put(DESCRIPTION_COLUMN, ""); + if (null == result.get(DESCRIPTION_COLUMN)) result.put(DESCRIPTION_COLUMN, ""); // File name - this is an asset, so it works as an already deleted file. // hence, we need to supply a non-existent file name. Anything will // do as long as it returns false when tested with File#exist(), and // the empty string does not, so it's set to "_". - if (!result.containsKey(LOCAL_FILENAME_COLUMN)) result.put(LOCAL_FILENAME_COLUMN, "_"); + if (null == result.get(LOCAL_FILENAME_COLUMN)) result.put(LOCAL_FILENAME_COLUMN, "_"); // No remote file name : this can't be downloaded. Unless specified. - if (!result.containsKey(REMOTE_FILENAME_COLUMN)) result.put(REMOTE_FILENAME_COLUMN, ""); + if (null == result.get(REMOTE_FILENAME_COLUMN)) result.put(REMOTE_FILENAME_COLUMN, ""); // 0 for the update date : 1970/1/1. Unless specified. - if (!result.containsKey(DATE_COLUMN)) result.put(DATE_COLUMN, 0); + if (null == result.get(DATE_COLUMN)) result.put(DATE_COLUMN, 0); // Checksum unknown unless specified - if (!result.containsKey(CHECKSUM_COLUMN)) result.put(CHECKSUM_COLUMN, ""); + if (null == result.get(CHECKSUM_COLUMN)) result.put(CHECKSUM_COLUMN, ""); // No filesize unless specified - if (!result.containsKey(FILESIZE_COLUMN)) result.put(FILESIZE_COLUMN, 0); + if (null == result.get(FILESIZE_COLUMN)) result.put(FILESIZE_COLUMN, 0); // Smallest possible version unless specified - if (!result.containsKey(VERSION_COLUMN)) result.put(VERSION_COLUMN, 1); + if (null == result.get(VERSION_COLUMN)) result.put(VERSION_COLUMN, 1); // Assume current format unless specified - if (!result.containsKey(FORMATVERSION_COLUMN)) + if (null == result.get(FORMATVERSION_COLUMN)) result.put(FORMATVERSION_COLUMN, UpdateHandler.MAXIMUM_SUPPORTED_FORMAT_VERSION); // No flags unless specified - if (!result.containsKey(FLAGS_COLUMN)) result.put(FLAGS_COLUMN, 0); + if (null == result.get(FLAGS_COLUMN)) result.put(FLAGS_COLUMN, 0); return result; } diff --git a/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java index df7bad8d0..9d478491a 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java +++ b/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java @@ -30,6 +30,7 @@ import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Iterator; import java.util.Locale; /** @@ -301,12 +302,14 @@ public class DictionaryInfoUtils { private static void addOrUpdateDictInfo(final ArrayList<DictionaryInfo> dictList, final DictionaryInfo newElement) { - for (final DictionaryInfo info : dictList) { - if (info.mLocale.equals(newElement.mLocale)) { - if (newElement.mVersion <= info.mVersion) { + final Iterator<DictionaryInfo> iter = dictList.iterator(); + while (iter.hasNext()) { + final DictionaryInfo thisDictInfo = iter.next(); + if (thisDictInfo.mLocale.equals(newElement.mLocale)) { + if (newElement.mVersion <= thisDictInfo.mVersion) { return; } - dictList.remove(info); + iter.remove(); } } dictList.add(newElement); diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index 0dd302afa..94513e635 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -54,13 +54,6 @@ public final class RichInputMethodManager { return sInstance; } - // Caveat: This may cause IPC - public static boolean isInputMethodManagerValidForUserOfThisProcess(final Context context) { - // Basically called to check whether this IME has been triggered by the current user or not - return !((InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE)). - getInputMethodList().isEmpty(); - } - public static void init(final Context context) { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); sInstance.initInternal(context, prefs); diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 282b5794f..1eca68ae5 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -43,20 +43,23 @@ public final class SubtypeSwitcher { private static final String TAG = SubtypeSwitcher.class.getSimpleName(); private static final SubtypeSwitcher sInstance = new SubtypeSwitcher(); + private /* final */ RichInputMethodManager mRichImm; private /* final */ Resources mResources; private /* final */ ConnectivityManager mConnectivityManager; - /*-----------------------------------------------------------*/ - // Variants which should be changed only by reload functions. - private NeedsToDisplayLanguage mNeedsToDisplayLanguage = new NeedsToDisplayLanguage(); + private final NeedsToDisplayLanguage mNeedsToDisplayLanguage = new NeedsToDisplayLanguage(); private InputMethodInfo mShortcutInputMethodInfo; private InputMethodSubtype mShortcutSubtype; private InputMethodSubtype mNoLanguageSubtype; - /*-----------------------------------------------------------*/ - private boolean mIsNetworkConnected; + // Dummy no language QWERTY subtype. See {@link R.xml.method}. + private static final InputMethodSubtype DUMMY_NO_LANGUAGE_SUBTYPE = new InputMethodSubtype( + R.string.subtype_no_language_qwerty, R.drawable.ic_subtype_keyboard, "zz", "keyboard", + "KeyboardLayoutSet=qwerty,AsciiCapable,EnabledWhenDefaultIsNotAsciiCapable", + false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */); + static final class NeedsToDisplayLanguage { private int mEnabledSubtypeCount; private boolean mIsSystemLanguageSameAsInputLanguage; @@ -96,11 +99,6 @@ public final class SubtypeSwitcher { mRichImm = RichInputMethodManager.getInstance(); mConnectivityManager = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE); - mNoLanguageSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( - SubtypeLocale.NO_LANGUAGE, SubtypeLocale.QWERTY); - if (mNoLanguageSubtype == null) { - throw new RuntimeException("Can't find no lanugage with QWERTY subtype"); - } final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); mIsNetworkConnected = (info != null && info.isConnected()); @@ -255,10 +253,20 @@ public final class SubtypeSwitcher { } public InputMethodSubtype getCurrentSubtype() { - return mRichImm.getCurrentInputMethodSubtype(mNoLanguageSubtype); + return mRichImm.getCurrentInputMethodSubtype(getNoLanguageSubtype()); } public InputMethodSubtype getNoLanguageSubtype() { - return mNoLanguageSubtype; + if (mNoLanguageSubtype == null) { + mNoLanguageSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + SubtypeLocale.NO_LANGUAGE, SubtypeLocale.QWERTY); + } + if (mNoLanguageSubtype != null) { + return mNoLanguageSubtype; + } + Log.w(TAG, "Can't find no lanugage with QWERTY subtype"); + Log.w(TAG, "No input method subtype found; return dummy subtype: " + + DUMMY_NO_LANGUAGE_SUBTYPE); + return DUMMY_NO_LANGUAGE_SUBTYPE; } } diff --git a/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java b/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java index 604ebeeb6..63d2fecd3 100644 --- a/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java +++ b/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java @@ -25,9 +25,9 @@ import android.content.pm.PackageManager; import android.os.Process; import android.preference.PreferenceManager; import android.util.Log; +import android.view.inputmethod.InputMethodManager; import com.android.inputmethod.compat.IntentCompatUtils; -import com.android.inputmethod.latin.RichInputMethodManager; import com.android.inputmethod.latin.Settings; /** @@ -65,17 +65,16 @@ public final class LauncherIconVisibilityManager extends BroadcastReceiver { } // The process that hosts this broadcast receiver is invoked and remains alive even after - // 1) the package has been re-installed, 2) the device has been booted, - // 3) a multiuser has been created. + // 1) the package has been re-installed, 2) the device has just booted, + // 3) a new user has been created. // There is no good reason to keep the process alive if this IME isn't a current IME. - final boolean isCurrentImeOfCurrentUser; - if (RichInputMethodManager.isInputMethodManagerValidForUserOfThisProcess(context)) { - RichInputMethodManager.init(context); - isCurrentImeOfCurrentUser = SetupActivity.isThisImeCurrent(context); - } else { - isCurrentImeOfCurrentUser = false; - } - + final InputMethodManager imm = + (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE); + // Called to check whether this IME has been triggered by the current user or not + final boolean isInputMethodManagerValidForUserOfThisProcess = + !imm.getInputMethodList().isEmpty(); + final boolean isCurrentImeOfCurrentUser = isInputMethodManagerValidForUserOfThisProcess + && SetupActivity.isThisImeCurrent(context, imm); if (!isCurrentImeOfCurrentUser) { final int myPid = Process.myPid(); Log.i(TAG, "Killing my process: pid=" + myPid); diff --git a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java index 8a2de887d..a68f98fe7 100644 --- a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java +++ b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java @@ -24,8 +24,6 @@ import android.provider.Settings; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; -import com.android.inputmethod.latin.RichInputMethodManager; - public final class SetupActivity extends Activity { @Override protected void onCreate(final Bundle savedInstanceState) { @@ -40,17 +38,24 @@ public final class SetupActivity extends Activity { } } + /* + * We may not be able to get our own {@link InputMethodInfo} just after this IME is installed + * because {@link InputMethodManagerService} may not be aware of this IME yet. + * Note: {@link RichInputMethodManager} has similar methods. Here in setup wizard, we can't + * use it for the reason above. + */ + /** * Check if the IME specified by the context is enabled. - * Note that {@link RichInputMethodManager} must have been initialized before calling this - * method. + * CAVEAT: This may cause a round trip IPC. * * @param context package context of the IME to be checked. + * @param imm the {@link InputMethodManager}. * @return true if this IME is enabled. */ - public static boolean isThisImeEnabled(final Context context) { + /* package */ static boolean isThisImeEnabled(final Context context, + final InputMethodManager imm) { final String packageName = context.getPackageName(); - final InputMethodManager imm = RichInputMethodManager.getInstance().getInputMethodManager(); for (final InputMethodInfo imi : imm.getEnabledInputMethodList()) { if (packageName.equals(imi.getPackageName())) { return true; @@ -61,17 +66,36 @@ public final class SetupActivity extends Activity { /** * Check if the IME specified by the context is the current IME. - * Note that {@link RichInputMethodManager} must have been initialized before calling this - * method. + * CAVEAT: This may cause a round trip IPC. * * @param context package context of the IME to be checked. + * @param imm the {@link InputMethodManager}. * @return true if this IME is the current IME. */ - public static boolean isThisImeCurrent(final Context context) { - final InputMethodInfo myImi = - RichInputMethodManager.getInstance().getInputMethodInfoOfThisIme(); + /* package */ static boolean isThisImeCurrent(final Context context, + final InputMethodManager imm) { + final InputMethodInfo imi = getInputMethodInfoOf(context.getPackageName(), imm); final String currentImeId = Settings.Secure.getString( context.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); - return myImi.getId().equals(currentImeId); + return imi != null && imi.getId().equals(currentImeId); + } + + /** + * Get {@link InputMethodInfo} of the IME specified by the package name. + * CAVEAT: This may cause a round trip IPC. + * + * @param packageName package name of the IME. + * @param imm the {@link InputMethodManager}. + * @return the {@link InputMethodInfo} of the IME specified by the <code>packageName</code>, + * or null if not found. + */ + /* package */ static InputMethodInfo getInputMethodInfoOf(final String packageName, + final InputMethodManager imm) { + for (final InputMethodInfo imi : imm.getInputMethodList()) { + if (packageName.equals(imi.getPackageName())) { + return imi; + } + } + return null; } } diff --git a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java index 78a6478c6..13fa9d9c8 100644 --- a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java +++ b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java @@ -28,6 +28,7 @@ import android.provider.Settings; import android.util.Log; import android.view.View; import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; import android.widget.ImageView; import android.widget.TextView; import android.widget.VideoView; @@ -36,7 +37,6 @@ import com.android.inputmethod.compat.TextViewCompatUtils; import com.android.inputmethod.compat.ViewCompatUtils; import com.android.inputmethod.latin.CollectionUtils; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.RichInputMethodManager; import com.android.inputmethod.latin.SettingsActivity; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; @@ -48,6 +48,8 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL private static final boolean ENABLE_WELCOME_VIDEO = true; + private InputMethodManager mImm; + private View mSetupWizard; private View mWelcomeScreen; private View mSetupScreen; @@ -69,15 +71,19 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL private static final int STEP_LAUNCHING_IME_SETTINGS = 4; private static final int STEP_BACK_FROM_IME_SETTINGS = 5; - final SettingsPoolingHandler mHandler = new SettingsPoolingHandler(this); + private SettingsPoolingHandler mHandler; - static final class SettingsPoolingHandler + private static final class SettingsPoolingHandler extends StaticInnerHandlerWrapper<SetupWizardActivity> { private static final int MSG_POLLING_IME_SETTINGS = 0; private static final long IME_SETTINGS_POLLING_INTERVAL = 200; - public SettingsPoolingHandler(final SetupWizardActivity outerInstance) { + private final InputMethodManager mImmInHandler; + + public SettingsPoolingHandler(final SetupWizardActivity outerInstance, + final InputMethodManager imm) { super(outerInstance); + mImmInHandler = imm; } @Override @@ -88,7 +94,7 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL } switch (msg.what) { case MSG_POLLING_IME_SETTINGS: - if (SetupActivity.isThisImeEnabled(setupWizardActivity)) { + if (SetupActivity.isThisImeEnabled(setupWizardActivity, mImmInHandler)) { setupWizardActivity.invokeSetupWizardOfThisIme(); return; } @@ -112,11 +118,12 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL setTheme(android.R.style.Theme_Translucent_NoTitleBar); super.onCreate(savedInstanceState); + mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); + mHandler = new SettingsPoolingHandler(this, mImm); + setContentView(R.layout.setup_wizard); mSetupWizard = findViewById(R.id.setup_wizard); - RichInputMethodManager.init(this); - if (savedInstanceState == null) { mStepNumber = determineSetupStepNumberFromLauncher(); } else { @@ -143,11 +150,12 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL R.string.setup_step1_title, R.string.setup_step1_instruction, R.string.setup_step1_finished_instruction, R.drawable.ic_setup_step1, R.string.setup_step1_action); + final SettingsPoolingHandler handler = mHandler; step1.setAction(new Runnable() { @Override public void run() { invokeLanguageAndInputSettings(); - mHandler.startPollingImeSettings(); + handler.startPollingImeSettings(); } }); mSetupStepGroup.addStep(step1); @@ -265,14 +273,15 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL void invokeInputMethodPicker() { // Invoke input method picker. - RichInputMethodManager.getInstance().getInputMethodManager() - .showInputMethodPicker(); + mImm.showInputMethodPicker(); mNeedsToAdjustStepNumberToSystemState = true; } void invokeSubtypeEnablerOfThisIme() { - final InputMethodInfo imi = - RichInputMethodManager.getInstance().getInputMethodInfoOfThisIme(); + final InputMethodInfo imi = SetupActivity.getInputMethodInfoOf(getPackageName(), mImm); + if (imi == null) { + return; + } final Intent intent = new Intent(); intent.setAction(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS); intent.addCategory(Intent.CATEGORY_DEFAULT); @@ -293,10 +302,10 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL private int determineSetupStepNumber() { mHandler.cancelPollingImeSettings(); - if (!SetupActivity.isThisImeEnabled(this)) { + if (!SetupActivity.isThisImeEnabled(this, mImm)) { return STEP_1; } - if (!SetupActivity.isThisImeCurrent(this)) { + if (!SetupActivity.isThisImeCurrent(this, mImm)) { return STEP_2; } return STEP_3; diff --git a/java/src/com/android/inputmethod/latin/utils/Base64Reader.java b/java/src/com/android/inputmethod/latin/utils/Base64Reader.java new file mode 100644 index 000000000..3eca6e744 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/Base64Reader.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2013 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.utils; + +import com.android.inputmethod.annotations.UsedForTesting; + +import java.io.EOFException; +import java.io.IOException; +import java.io.LineNumberReader; + +@UsedForTesting +public class Base64Reader { + private final LineNumberReader mReader; + + private String mLine; + private int mCharPos; + private int mByteCount; + + @UsedForTesting + public Base64Reader(final LineNumberReader reader) { + mReader = reader; + reset(); + } + + @UsedForTesting + public void reset() { + mLine = null; + mCharPos = 0; + mByteCount = 0; + } + + @UsedForTesting + public int getLineNumber() { + return mReader.getLineNumber(); + } + + @UsedForTesting + public int getByteCount() { + return mByteCount; + } + + private void fillBuffer() throws IOException { + if (mLine == null || mCharPos >= mLine.length()) { + mLine = mReader.readLine(); + mCharPos = 0; + } + if (mLine == null) { + throw new EOFException(); + } + } + + private int peekUint8() throws IOException { + fillBuffer(); + final char c = mLine.charAt(mCharPos); + if (c >= 'A' && c <= 'Z') + return c - 'A' + 0; + if (c >= 'a' && c <= 'z') + return c - 'a' + 26; + if (c >= '0' && c <= '9') + return c - '0' + 52; + if (c == '+') + return 62; + if (c == '/') + return 63; + if (c == '=') + return 0; + throw new RuntimeException("Unknown character '" + c + "' in base64 at line " + + mReader.getLineNumber()); + } + + private int getUint8() throws IOException { + final int value = peekUint8(); + mCharPos++; + return value; + } + + @UsedForTesting + public int readUint8() throws IOException { + final int value1, value2; + switch (mByteCount % 3) { + case 0: + value1 = getUint8() << 2; + value2 = value1 | (peekUint8() >> 4); + break; + case 1: + value1 = (getUint8() & 0x0f) << 4; + value2 = value1 | (peekUint8() >> 2); + break; + default: + value1 = (getUint8() & 0x03) << 6; + value2 = value1 | getUint8(); + break; + } + mByteCount++; + return value2; + } + + @UsedForTesting + public short readInt16() throws IOException { + final int data = readUint8() << 8; + return (short)(data | readUint8()); + } +} |