am 7058b02a: Extract a new class for app-specific workarounds.

* commit '7058b02a9c798c21b169b778be2befc7739f4e9b':
  Extract a new class for app-specific workarounds.
main
Jean Chalard 2013-05-20 19:49:25 -07:00 committed by Android Git Automerger
commit 5906b05bb5
4 changed files with 88 additions and 40 deletions

View File

@ -0,0 +1,53 @@
/*
* 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
public void setPackageInfo(final PackageInfo packageInfo) {
mPackageInfo = packageInfo;
}
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();
}
}

View File

@ -75,7 +75,7 @@ public final class DictionaryPackInstallBroadcastReceiver extends BroadcastRecei
final String packageName = packageUri.getSchemeSpecificPart(); final String packageName = packageUri.getSchemeSpecificPart();
if (null == packageName) return; if (null == packageName) return;
// TODO: do this in a more appropriate place // TODO: do this in a more appropriate place
TargetApplicationGetter.removeApplicationInfoCache(packageName); TargetPackageInfoGetterTask.removeCachedPackageInfo(packageName);
final PackageInfo packageInfo; final PackageInfo packageInfo;
try { try {
packageInfo = manager.getPackageInfo(packageName, PackageManager.GET_PROVIDERS); packageInfo = manager.getPackageInfo(packageName, PackageManager.GET_PROVIDERS);

View File

@ -28,14 +28,13 @@ import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Rect; import android.graphics.Rect;
import android.inputmethodservice.InputMethodService; import android.inputmethodservice.InputMethodService;
import android.media.AudioManager; import android.media.AudioManager;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.os.Build.VERSION_CODES;
import android.os.Debug; import android.os.Debug;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
@ -64,6 +63,7 @@ import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.compat.AppWorkaroundsUtils;
import com.android.inputmethod.compat.InputMethodServiceCompatUtils; import com.android.inputmethod.compat.InputMethodServiceCompatUtils;
import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.compat.SuggestionSpanUtils;
import com.android.inputmethod.dictionarypack.DictionaryPackConstants; import com.android.inputmethod.dictionarypack.DictionaryPackConstants;
@ -91,7 +91,7 @@ import java.util.TreeSet;
* Input method implementation for Qwerty'ish keyboard. * Input method implementation for Qwerty'ish keyboard.
*/ */
public class LatinIME extends InputMethodService implements KeyboardActionListener, public class LatinIME extends InputMethodService implements KeyboardActionListener,
SuggestionStripView.Listener, TargetApplicationGetter.OnTargetApplicationKnownListener, SuggestionStripView.Listener, TargetPackageInfoGetterTask.OnTargetPackageInfoKnownListener,
Suggest.SuggestInitializationListener { Suggest.SuggestInitializationListener {
private static final String TAG = LatinIME.class.getSimpleName(); private static final String TAG = LatinIME.class.getSimpleName();
private static final boolean TRACE = false; private static final boolean TRACE = false;
@ -141,7 +141,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
@UsedForTesting Suggest mSuggest; @UsedForTesting Suggest mSuggest;
private CompletionInfo[] mApplicationSpecifiedCompletions; private CompletionInfo[] mApplicationSpecifiedCompletions;
private ApplicationInfo mTargetApplicationInfo; private AppWorkaroundsUtils mAppWorkAroundsUtils = new AppWorkaroundsUtils();
private RichInputMethodManager mRichImm; private RichInputMethodManager mRichImm;
@UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; @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"); Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead");
} }
mTargetApplicationInfo = final PackageInfo packageInfo =
TargetApplicationGetter.getCachedApplicationInfo(editorInfo.packageName); TargetPackageInfoGetterTask.getCachedPackageInfo(editorInfo.packageName);
if (null == mTargetApplicationInfo) { mAppWorkAroundsUtils.setPackageInfo(packageInfo);
new TargetApplicationGetter(this /* context */, this /* listener */) if (null == packageInfo) {
new TargetPackageInfoGetterTask(this /* context */, this /* listener */)
.execute(editorInfo.packageName); .execute(editorInfo.packageName);
} }
@ -819,10 +820,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
} }
// Callback for the TargetApplicationGetter // Callback for the TargetPackageInfoGetterTask
@Override @Override
public void onTargetApplicationKnown(final ApplicationInfo info) { public void onTargetPackageInfoKnown(final PackageInfo info) {
mTargetApplicationInfo = info; mAppWorkAroundsUtils.setPackageInfo(info);
} }
@Override @Override
@ -1369,8 +1370,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return; return;
} }
if (Constants.CODE_ENTER == code && mTargetApplicationInfo != null if (Constants.CODE_ENTER == code && mAppWorkAroundsUtils.isBeforeJellyBean()) {
&& mTargetApplicationInfo.targetSdkVersion < VERSION_CODES.JELLY_BEAN) {
// Backward compatibility mode. Before Jelly bean, the keyboard would simulate // Backward compatibility mode. Before Jelly bean, the keyboard would simulate
// a hardware keyboard event on pressing enter or delete. This is bad for many // 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 // 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. // This should never happen.
Log.e(TAG, "Backspace when we don't know the selection position"); Log.e(TAG, "Backspace when we don't know the selection position");
} }
if (mTargetApplicationInfo != null if (mAppWorkAroundsUtils.isBeforeJellyBean()) {
&& mTargetApplicationInfo.targetSdkVersion < VERSION_CODES.JELLY_BEAN) {
// Backward compatibility mode. Before Jelly bean, the keyboard would simulate // Backward compatibility mode. Before Jelly bean, the keyboard would simulate
// a hardware keyboard event on pressing enter or delete. This is bad for many // 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 // reasons (there are race conditions with commits) but some applications are
@ -2785,12 +2784,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} }
public void debugDumpStateAndCrashWithException(final String context) { public void debugDumpStateAndCrashWithException(final String context) {
final StringBuilder s = new StringBuilder(); final StringBuilder s = new StringBuilder(mAppWorkAroundsUtils.toString());
s.append("Target application : ").append(mTargetApplicationInfo.name) s.append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes)
.append("\nPackage : ").append(mTargetApplicationInfo.packageName)
.append("\nTarget app sdk version : ")
.append(mTargetApplicationInfo.targetSdkVersion)
.append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes)
.append("\nContext : ").append(context); .append("\nContext : ").append(context);
throw new RuntimeException(s.toString()); throw new RuntimeException(s.toString());
} }

View File

@ -17,54 +17,54 @@
package com.android.inputmethod.latin; package com.android.inputmethod.latin;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.LruCache; 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 final int MAX_CACHE_ENTRIES = 64; // arbitrary
private static LruCache<String, ApplicationInfo> sCache = private static final LruCache<String, PackageInfo> sCache =
new LruCache<String, ApplicationInfo>(MAX_CACHE_ENTRIES); 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; if (null == packageName) return null;
return sCache.get(packageName); return sCache.get(packageName);
} }
public static void removeApplicationInfoCache(final String packageName) { public static void removeCachedPackageInfo(final String packageName) {
sCache.remove(packageName); sCache.remove(packageName);
} }
public interface OnTargetApplicationKnownListener { public interface OnTargetPackageInfoKnownListener {
public void onTargetApplicationKnown(final ApplicationInfo info); public void onTargetPackageInfoKnown(final PackageInfo info);
} }
private Context mContext; private Context mContext;
private final OnTargetApplicationKnownListener mListener; private final OnTargetPackageInfoKnownListener mListener;
public TargetApplicationGetter(final Context context, public TargetPackageInfoGetterTask(final Context context,
final OnTargetApplicationKnownListener listener) { final OnTargetPackageInfoKnownListener listener) {
mContext = context; mContext = context;
mListener = listener; mListener = listener;
} }
@Override @Override
protected ApplicationInfo doInBackground(final String... packageName) { protected PackageInfo doInBackground(final String... packageName) {
final PackageManager pm = mContext.getPackageManager(); final PackageManager pm = mContext.getPackageManager();
mContext = null; // Bazooka-powered anti-leak device mContext = null; // Bazooka-powered anti-leak device
try { try {
final ApplicationInfo targetAppInfo = final PackageInfo packageInfo = pm.getPackageInfo(packageName[0], 0 /* flags */);
pm.getApplicationInfo(packageName[0], 0 /* flags */); sCache.put(packageName[0], packageInfo);
sCache.put(packageName[0], targetAppInfo); return packageInfo;
return targetAppInfo;
} catch (android.content.pm.PackageManager.NameNotFoundException e) { } catch (android.content.pm.PackageManager.NameNotFoundException e) {
return null; return null;
} }
} }
@Override @Override
protected void onPostExecute(final ApplicationInfo info) { protected void onPostExecute(final PackageInfo info) {
mListener.onTargetApplicationKnown(info); mListener.onTargetPackageInfoKnown(info);
} }
} }