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

Commit d2c5533f authored by Tadashi G. Takaoka's avatar Tadashi G. Takaoka Committed by Android (Google) Code Review
Browse files

Merge "Add RunInLocale class to guard locale switching"

parents 56dda78d 16c6f355
Loading
Loading
Loading
Loading
+35 −27
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ import com.android.inputmethod.keyboard.KeyboardSet.Params.ElementParams;
import com.android.inputmethod.latin.InputTypeUtils;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.LocaleUtils;
import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StringUtils;
import com.android.inputmethod.latin.XmlParseUtils;
@@ -66,6 +66,7 @@ public class KeyboardSet {

    public static class KeyboardSetException extends RuntimeException {
        public final KeyboardId mKeyboardId;

        public KeyboardSetException(Throwable cause, KeyboardId keyboardId) {
            super(cause);
            mKeyboardId = keyboardId;
@@ -161,26 +162,29 @@ public class KeyboardSet {
        }
    }

    private Keyboard getKeyboard(Context context, ElementParams elementParams, KeyboardId id) {
        final Resources res = context.getResources();
    private Keyboard getKeyboard(Context context, ElementParams elementParams,
            final KeyboardId id) {
        final SoftReference<Keyboard> ref = sKeyboardCache.get(id);
        Keyboard keyboard = (ref == null) ? null : ref.get();
        if (keyboard == null) {
            final Locale savedLocale = LocaleUtils.setSystemLocale(res, id.mLocale);
            try {
            final Keyboard.Builder<Keyboard.Params> builder =
                        new Keyboard.Builder<Keyboard.Params>(context, new Keyboard.Params());
                    new Keyboard.Builder<Keyboard.Params>(mContext, new Keyboard.Params());
            if (id.isAlphabetKeyboard()) {
                builder.setAutoGenerate(sKeysCache);
            }
                builder.load(elementParams.mKeyboardXmlId, id);
            final int keyboardXmlId = elementParams.mKeyboardXmlId;
            final RunInLocale<Void> job = new RunInLocale<Void>() {
                @Override
                protected Void job(Resources res) {
                    builder.load(keyboardXmlId, id);
                    return null;
                }
            };
            job.runInLocale(context.getResources(), id.mLocale);
            builder.setTouchPositionCorrectionEnabled(mParams.mTouchPositionCorrectionEnabled);
            builder.setProximityCharsCorrectionEnabled(
                    elementParams.mProximityCharsCorrectionEnabled);
            keyboard = builder.build();
            } finally {
                LocaleUtils.setSystemLocale(res, savedLocale);
            }
            sKeyboardCache.put(id, new SoftReference<Keyboard>(keyboard));

            if (DEBUG_CACHE) {
@@ -271,16 +275,20 @@ public class KeyboardSet {
            if (mParams.mLocale == null)
                throw new RuntimeException("KeyboardSet subtype is not specified");

            final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, mParams.mLocale);
            final RunInLocale<Void> job = new RunInLocale<Void>() {
                @Override
                protected Void job(Resources res) {
                    try {
                parseKeyboardSet(mResources, R.xml.keyboard_set);
                        parseKeyboardSet(res, R.xml.keyboard_set);
                    } catch (Exception e) {
                        throw new RuntimeException(e.getMessage() + " in "
                        + mResources.getResourceName(R.xml.keyboard_set)
                                + res.getResourceName(R.xml.keyboard_set)
                                + " of locale " + mParams.mLocale);
            } finally {
                LocaleUtils.setSystemLocale(mResources, savedLocale);
                    }
                    return null;
                }
            };
            job.runInLocale(mResources, mParams.mLocale);
            return new KeyboardSet(mContext, mParams);
        }

+9 −5
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.util.Log;

import com.android.inputmethod.latin.LocaleUtils.RunInLocale;

import java.io.File;
import java.util.ArrayList;
import java.util.Locale;
@@ -154,11 +156,13 @@ class BinaryDictionaryGetter {
     */
    private static AssetFileAddress loadFallbackResource(final Context context,
            final int fallbackResId, final Locale locale) {
        final Resources res = context.getResources();
        final Locale savedLocale = LocaleUtils.setSystemLocale(res, locale);
        final AssetFileDescriptor afd = res.openRawResourceFd(fallbackResId);
        LocaleUtils.setSystemLocale(res, savedLocale);

        final RunInLocale<AssetFileDescriptor> job = new RunInLocale<AssetFileDescriptor>() {
            @Override
            protected AssetFileDescriptor job(Resources res) {
                return res.openRawResourceFd(fallbackResId);
            }
        };
        final AssetFileDescriptor afd = job.runInLocale(context.getResources(), locale);
        if (afd == null) {
            Log.e(TAG, "Found the resource but cannot read it. Is it compressed? resId="
                    + fallbackResId);
+40 −38
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.util.Log;

import com.android.inputmethod.latin.LocaleUtils.RunInLocale;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -30,7 +32,6 @@ import java.util.Locale;
 * Factory for dictionary instances.
 */
public class DictionaryFactory {

    private static String TAG = DictionaryFactory.class.getSimpleName();

    /**
@@ -98,14 +99,13 @@ public class DictionaryFactory {
            final int resId, final Locale locale) {
        AssetFileDescriptor afd = null;
        try {
            final Resources res = context.getResources();
            if (null != locale) {
                final Locale savedLocale = LocaleUtils.setSystemLocale(res, locale);
                afd = res.openRawResourceFd(resId);
                LocaleUtils.setSystemLocale(res, savedLocale);
            } else {
                afd = res.openRawResourceFd(resId);
            final RunInLocale<AssetFileDescriptor> job = new RunInLocale<AssetFileDescriptor>() {
                @Override
                protected AssetFileDescriptor job(Resources res) {
                    return res.openRawResourceFd(resId);
                }
            };
            afd = job.runInLocale(context.getResources(), locale);
            if (afd == null) {
                Log.e(TAG, "Found the resource but it is compressed. resId=" + resId);
                return null;
@@ -161,9 +161,9 @@ public class DictionaryFactory {
     * @return whether a (non-placeholder) dictionary is available or not.
     */
    public static boolean isDictionaryAvailable(Context context, Locale locale) {
        final Resources res = context.getResources();
        final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale);

        final RunInLocale<Boolean> job = new RunInLocale<Boolean>() {
            @Override
            protected Boolean job(Resources res) {
                final int resourceId = getMainDictionaryResourceId(res);
                final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
                final boolean hasDictionary = isFullDictionary(afd);
@@ -172,16 +172,17 @@ public class DictionaryFactory {
                } catch (java.io.IOException e) {
                    /* Um, what can we do here exactly? */
                }

        LocaleUtils.setSystemLocale(res, saveLocale);
                return hasDictionary;
            }
        };
        return job.runInLocale(context.getResources(), locale);
    }

    // TODO: Do not use the size of the dictionary as an unique dictionary ID.
    public static Long getDictionaryId(final Context context, final Locale locale) {
        final Resources res = context.getResources();
        final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale);

        final RunInLocale<Long> job = new RunInLocale<Long>() {
            @Override
            protected Long job(Resources res) {
                final int resourceId = getMainDictionaryResourceId(res);
                final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
                final Long size = (afd != null && afd.getLength() > PLACEHOLDER_LENGTH)
@@ -191,10 +192,11 @@ public class DictionaryFactory {
                    if (null != afd) afd.close();
                } catch (java.io.IOException e) {
                }

        LocaleUtils.setSystemLocale(res, saveLocale);
                return size;
            }
        };
        return job.runInLocale(context.getResources(), locale);
    }

    // TODO: Find the Right Way to find out whether the resource is a placeholder or not.
    // Suggestion : strip the locale, open the placeholder file and store its offset.
+35 −24
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.LatinKeyboardView;
import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.suggestions.SuggestionsView;

@@ -478,7 +479,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
    // Has to be package-visible for unit tests
    /* package */ void loadSettings() {
        if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        mSettingsValues = new SettingsValues(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr());
        final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() {
            @Override
            protected SettingsValues job(Resources res) {
                return new SettingsValues(mPrefs, LatinIME.this);
            }
        };
        mSettingsValues = job.runInLocale(mResources, mSubtypeSwitcher.getInputLocale());
        mFeedbackManager = new AudioAndHapticFeedbackManager(this, mSettingsValues);
        resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
    }
@@ -487,8 +494,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
        final Locale keyboardLocale = mSubtypeSwitcher.getInputLocale();

        final Resources res = mResources;
        final Locale savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale);
        final Context context = this;
        final RunInLocale<Void> job = new RunInLocale<Void>() {
            @Override
            protected Void job(Resources res) {
                final ContactsDictionary oldContactsDictionary;
                if (mSuggest != null) {
                    oldContactsDictionary = mSuggest.getContactsDictionary();
@@ -498,22 +507,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                }

                int mainDicResId = DictionaryFactory.getMainDictionaryResourceId(res);
        mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
                mSuggest = new Suggest(context, mainDicResId, keyboardLocale);
                if (mSettingsValues.mAutoCorrectEnabled) {
                    mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
                }

        mUserDictionary = new UserDictionary(this, localeStr);
                mUserDictionary = new UserDictionary(context, localeStr);
                mSuggest.setUserDictionary(mUserDictionary);
                mIsUserDictionaryAvailable = mUserDictionary.isEnabled();

                resetContactsDictionary(oldContactsDictionary);

                mUserHistoryDictionary
                = new UserHistoryDictionary(this, localeStr, Suggest.DIC_USER_HISTORY);
                    = new UserHistoryDictionary(context, localeStr, Suggest.DIC_USER_HISTORY);
                mSuggest.setUserHistoryDictionary(mUserHistoryDictionary);

        LocaleUtils.setSystemLocale(res, savedLocale);
                return null;
            }
        };
        job.runInLocale(mResources, keyboardLocale);
    }

    /**
+29 −14
Original line number Diff line number Diff line
@@ -161,21 +161,36 @@ public class LocaleUtils {
        return LOCALE_MATCH <= level;
    }

    static final Object sLockForRunInLocale = new Object();

    public abstract static class RunInLocale<T> {
        protected abstract T job(Resources res);

        /**
     * Sets the system locale for this process.
         * Execute {@link #job(Resources)} method in specified system locale exclusively.
         *
         * @param res the resources to use. Pass current resources.
     * @param newLocale the locale to change to.
     * @return the old locale.
         * @param newLocale the locale to change to
         * @return the value returned from {@link #job(Resources)}.
         */
    public static synchronized Locale setSystemLocale(final Resources res, final Locale newLocale) {
        public T runInLocale(final Resources res, final Locale newLocale) {
            synchronized (sLockForRunInLocale) {
                final Configuration conf = res.getConfiguration();
                final Locale oldLocale = conf.locale;
                try {
                    if (newLocale != null && !newLocale.equals(oldLocale)) {
                        conf.locale = newLocale;
                        res.updateConfiguration(conf, res.getDisplayMetrics());
                    }
        return oldLocale;
                    return job(res);
                } finally {
                    if (newLocale != null && !newLocale.equals(oldLocale)) {
                        conf.locale = oldLocale;
                        res.updateConfiguration(conf, res.getDisplayMetrics());
                    }
                }
            }
        }
    }

    private static final HashMap<String, Locale> sLocaleCache = new HashMap<String, Locale>();
Loading