Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7058b02a authored by Jean Chalard's avatar Jean Chalard
Browse files

Extract a new class for app-specific workarounds.

Bug: 8944307
Change-Id: Iaff9dd03d3d856a6bdaa2b16c4e71e95cd2b6349
parent b1e37e4a
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
/*
 * 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();
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -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);
+16 −21
Original line number Diff line number Diff line
@@ -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
@@ -2785,12 +2784,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());
    }
+18 −18
Original line number Diff line number Diff line
@@ -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);
    }
}