diff options
Diffstat (limited to 'java/src')
-rw-r--r-- | java/src/com/android/inputmethod/compat/AppWorkaroundsHelper.java | 29 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/compat/AppWorkaroundsUtils.java | 60 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java | 2 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/LatinIME.java | 41 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/RichInputMethodManager.java | 7 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/TargetPackageInfoGetterTask.java (renamed from java/src/com/android/inputmethod/latin/TargetApplicationGetter.java) | 36 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java | 11 |
7 files changed, 144 insertions, 42 deletions
diff --git a/java/src/com/android/inputmethod/compat/AppWorkaroundsHelper.java b/java/src/com/android/inputmethod/compat/AppWorkaroundsHelper.java new file mode 100644 index 000000000..21535e421 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/AppWorkaroundsHelper.java @@ -0,0 +1,29 @@ +/* + * 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.compat; + +import android.content.pm.PackageInfo; + +public class AppWorkaroundsHelper { + private AppWorkaroundsHelper() { + // This helper class is not publicly instantiable. + } + + public static boolean evaluateIsBrokenByRecorrection(final PackageInfo info) { + return false; + } +} diff --git a/java/src/com/android/inputmethod/compat/AppWorkaroundsUtils.java b/java/src/com/android/inputmethod/compat/AppWorkaroundsUtils.java new file mode 100644 index 000000000..7e9e2e37b --- /dev/null +++ b/java/src/com/android/inputmethod/compat/AppWorkaroundsUtils.java @@ -0,0 +1,60 @@ +/* + * 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.compat; + +import android.content.pm.PackageInfo; +import android.os.Build.VERSION_CODES; + +/** + * A class to encapsulate work-arounds specific to particular apps. + */ +public class AppWorkaroundsUtils { + private PackageInfo mPackageInfo; // May be null + private boolean mIsBrokenByRecorrection = false; + + public void setPackageInfo(final PackageInfo packageInfo) { + mPackageInfo = packageInfo; + mIsBrokenByRecorrection = AppWorkaroundsHelper.evaluateIsBrokenByRecorrection( + packageInfo); + } + + public boolean isBrokenByRecorrection() { + return mIsBrokenByRecorrection; + } + + public boolean isBeforeJellyBean() { + if (null == mPackageInfo || null == mPackageInfo.applicationInfo) { + return false; + } + return mPackageInfo.applicationInfo.targetSdkVersion < VERSION_CODES.JELLY_BEAN; + } + + @Override + public String toString() { + if (null == mPackageInfo || null == mPackageInfo.applicationInfo) { + return ""; + } + final StringBuilder s = new StringBuilder(); + s.append("Target application : ") + .append(mPackageInfo.applicationInfo.name) + .append("\nPackage : ") + .append(mPackageInfo.applicationInfo.packageName) + .append("\nTarget app sdk version : ") + .append(mPackageInfo.applicationInfo.targetSdkVersion); + return s.toString(); + } +} diff --git a/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java b/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java index 41fcb83e6..56096127e 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java +++ b/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java @@ -75,7 +75,7 @@ public final class DictionaryPackInstallBroadcastReceiver extends BroadcastRecei final String packageName = packageUri.getSchemeSpecificPart(); if (null == packageName) return; // TODO: do this in a more appropriate place - TargetApplicationGetter.removeApplicationInfoCache(packageName); + TargetPackageInfoGetterTask.removeCachedPackageInfo(packageName); final PackageInfo packageInfo; try { packageInfo = manager.getPackageInfo(packageName, PackageManager.GET_PROVIDERS); diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 347a4c63a..c464a7067 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -28,14 +28,13 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.net.ConnectivityManager; -import android.os.Build.VERSION_CODES; import android.os.Debug; import android.os.Handler; import android.os.HandlerThread; @@ -64,6 +63,7 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.compat.AppWorkaroundsUtils; import com.android.inputmethod.compat.InputMethodServiceCompatUtils; import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.dictionarypack.DictionaryPackConstants; @@ -91,7 +91,7 @@ import java.util.TreeSet; * Input method implementation for Qwerty'ish keyboard. */ public class LatinIME extends InputMethodService implements KeyboardActionListener, - SuggestionStripView.Listener, TargetApplicationGetter.OnTargetApplicationKnownListener, + SuggestionStripView.Listener, TargetPackageInfoGetterTask.OnTargetPackageInfoKnownListener, Suggest.SuggestInitializationListener { private static final String TAG = LatinIME.class.getSimpleName(); private static final boolean TRACE = false; @@ -141,7 +141,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; @UsedForTesting Suggest mSuggest; private CompletionInfo[] mApplicationSpecifiedCompletions; - private ApplicationInfo mTargetApplicationInfo; + private AppWorkaroundsUtils mAppWorkAroundsUtils = new AppWorkaroundsUtils(); private RichInputMethodManager mRichImm; @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; @@ -711,10 +711,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); } - mTargetApplicationInfo = - TargetApplicationGetter.getCachedApplicationInfo(editorInfo.packageName); - if (null == mTargetApplicationInfo) { - new TargetApplicationGetter(this /* context */, this /* listener */) + final PackageInfo packageInfo = + TargetPackageInfoGetterTask.getCachedPackageInfo(editorInfo.packageName); + mAppWorkAroundsUtils.setPackageInfo(packageInfo); + if (null == packageInfo) { + new TargetPackageInfoGetterTask(this /* context */, this /* listener */) .execute(editorInfo.packageName); } @@ -819,10 +820,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); } - // Callback for the TargetApplicationGetter + // Callback for the TargetPackageInfoGetterTask @Override - public void onTargetApplicationKnown(final ApplicationInfo info) { - mTargetApplicationInfo = info; + public void onTargetPackageInfoKnown(final PackageInfo info) { + mAppWorkAroundsUtils.setPackageInfo(info); } @Override @@ -1369,8 +1370,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return; } - if (Constants.CODE_ENTER == code && mTargetApplicationInfo != null - && mTargetApplicationInfo.targetSdkVersion < VERSION_CODES.JELLY_BEAN) { + if (Constants.CODE_ENTER == code && mAppWorkAroundsUtils.isBeforeJellyBean()) { // Backward compatibility mode. Before Jelly bean, the keyboard would simulate // a hardware keyboard event on pressing enter or delete. This is bad for many // reasons (there are race conditions with commits) but some applications are @@ -1864,8 +1864,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // This should never happen. Log.e(TAG, "Backspace when we don't know the selection position"); } - if (mTargetApplicationInfo != null - && mTargetApplicationInfo.targetSdkVersion < VERSION_CODES.JELLY_BEAN) { + if (mAppWorkAroundsUtils.isBeforeJellyBean()) { // Backward compatibility mode. Before Jelly bean, the keyboard would simulate // a hardware keyboard event on pressing enter or delete. This is bad for many // reasons (there are race conditions with commits) but some applications are @@ -2451,6 +2450,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen * do nothing. */ private void restartSuggestionsOnWordTouchedByCursor() { + // HACK: We may want to special-case some apps that exhibit bad behavior in case of + // recorrection. This is a temporary, stopgap measure that will be removed later. + // TODO: remove this. + if (mAppWorkAroundsUtils.isBrokenByRecorrection()) return; // If the cursor is not touching a word, or if there is a selection, return right away. if (mLastSelectionStart != mLastSelectionEnd) return; // If we don't know the cursor location, return. @@ -2785,12 +2788,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } public void debugDumpStateAndCrashWithException(final String context) { - final StringBuilder s = new StringBuilder(); - s.append("Target application : ").append(mTargetApplicationInfo.name) - .append("\nPackage : ").append(mTargetApplicationInfo.packageName) - .append("\nTarget app sdk version : ") - .append(mTargetApplicationInfo.targetSdkVersion) - .append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes) + final StringBuilder s = new StringBuilder(mAppWorkAroundsUtils.toString()); + s.append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes) .append("\nContext : ").append(context); throw new RuntimeException(s.toString()); } diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index 94513e635..0dd302afa 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -54,6 +54,13 @@ 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/TargetApplicationGetter.java b/java/src/com/android/inputmethod/latin/TargetPackageInfoGetterTask.java index 1ea4ac346..947b0c586 100644 --- a/java/src/com/android/inputmethod/latin/TargetApplicationGetter.java +++ b/java/src/com/android/inputmethod/latin/TargetPackageInfoGetterTask.java @@ -17,54 +17,54 @@ package com.android.inputmethod.latin; import android.content.Context; -import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.AsyncTask; import android.util.LruCache; -public final class TargetApplicationGetter extends AsyncTask<String, Void, ApplicationInfo> { +public final class TargetPackageInfoGetterTask extends + AsyncTask<String, Void, PackageInfo> { private static final int MAX_CACHE_ENTRIES = 64; // arbitrary - private static LruCache<String, ApplicationInfo> sCache = - new LruCache<String, ApplicationInfo>(MAX_CACHE_ENTRIES); + private static final LruCache<String, PackageInfo> sCache = + new LruCache<String, PackageInfo>(MAX_CACHE_ENTRIES); - public static ApplicationInfo getCachedApplicationInfo(final String packageName) { + public static PackageInfo getCachedPackageInfo(final String packageName) { if (null == packageName) return null; return sCache.get(packageName); } - public static void removeApplicationInfoCache(final String packageName) { + public static void removeCachedPackageInfo(final String packageName) { sCache.remove(packageName); } - public interface OnTargetApplicationKnownListener { - public void onTargetApplicationKnown(final ApplicationInfo info); + public interface OnTargetPackageInfoKnownListener { + public void onTargetPackageInfoKnown(final PackageInfo info); } private Context mContext; - private final OnTargetApplicationKnownListener mListener; + private final OnTargetPackageInfoKnownListener mListener; - public TargetApplicationGetter(final Context context, - final OnTargetApplicationKnownListener listener) { + public TargetPackageInfoGetterTask(final Context context, + final OnTargetPackageInfoKnownListener listener) { mContext = context; mListener = listener; } @Override - protected ApplicationInfo doInBackground(final String... packageName) { + protected PackageInfo doInBackground(final String... packageName) { final PackageManager pm = mContext.getPackageManager(); mContext = null; // Bazooka-powered anti-leak device try { - final ApplicationInfo targetAppInfo = - pm.getApplicationInfo(packageName[0], 0 /* flags */); - sCache.put(packageName[0], targetAppInfo); - return targetAppInfo; + final PackageInfo packageInfo = pm.getPackageInfo(packageName[0], 0 /* flags */); + sCache.put(packageName[0], packageInfo); + return packageInfo; } catch (android.content.pm.PackageManager.NameNotFoundException e) { return null; } } @Override - protected void onPostExecute(final ApplicationInfo info) { - mListener.onTargetApplicationKnown(info); + protected void onPostExecute(final PackageInfo info) { + mListener.onTargetPackageInfoKnown(info); } } diff --git a/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java b/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java index 1b893a65d..6a7cd9b6f 100644 --- a/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java +++ b/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java @@ -68,8 +68,15 @@ public final class LauncherIconVisibilityManager extends BroadcastReceiver { // 1) the package has been re-installed, 2) the device has been booted, // 3) a multiuser has been created. // There is no good reason to keep the process alive if this IME isn't a current IME. - RichInputMethodManager.init(context); - if (!SetupActivity.isThisImeCurrent(context)) { + final boolean isCurrentImeOfCurrentUser; + if (RichInputMethodManager.isInputMethodManagerValidForUserOfThisProcess(context)) { + RichInputMethodManager.init(context); + isCurrentImeOfCurrentUser = SetupActivity.isThisImeCurrent(context); + } else { + isCurrentImeOfCurrentUser = false; + } + + if (!isCurrentImeOfCurrentUser) { final int myPid = Process.myPid(); Log.i(TAG, "Killing my process: pid=" + myPid); Process.killProcess(myPid); |