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

Commit afcd19c7 authored by Tony Mak's avatar Tony Mak
Browse files

Optimize filterByLanguage by caching locale objects

According to traceview, most of the time spent in filterByLanguage
is calling getLocaleObject to create java.util.Locale objects.
The solution is to cache the object to save the cost. Note that both
mSubtypeLangugageTag and mSubtypeLocale are final, so it is fine to
cache the locale object.

Test: bit FrameworksCoreTests:android.view.inputmethod.InputMethodSubtypeTest
Test: bit FrameworksCoreTests:com.android.internal.inputmethod.LocaleUtilsTest
Test: Try to switch user back and forth, and tap a textview to show IME.

Bug: 37647204
Fix: 37647213

Change-Id: Ib6ff7e97b17fc547c8109af8177f05fc3ea41b08
parent 8ce50255
Loading
Loading
Loading
Loading
+16 −4
Original line number Diff line number Diff line
@@ -84,6 +84,8 @@ public final class InputMethodSubtype implements Parcelable {
    private final String mSubtypeLanguageTag;
    private final String mSubtypeMode;
    private final String mSubtypeExtraValue;
    private final Object mLock = new Object();
    private volatile Locale mCachedLocaleObj;
    private volatile HashMap<String, String> mExtraValueHashMapCache;

    /**
@@ -372,10 +374,20 @@ public final class InputMethodSubtype implements Parcelable {
     */
    @Nullable
    public Locale getLocaleObject() {
        if (mCachedLocaleObj != null) {
            return mCachedLocaleObj;
        }
        synchronized (mLock) {
            if (mCachedLocaleObj != null) {
                return mCachedLocaleObj;
            }
            if (!TextUtils.isEmpty(mSubtypeLanguageTag)) {
            return Locale.forLanguageTag(mSubtypeLanguageTag);
                mCachedLocaleObj = Locale.forLanguageTag(mSubtypeLanguageTag);
            } else {
                mCachedLocaleObj = InputMethodUtils.constructLocaleFromString(mSubtypeLocale);
            }
            return mCachedLocaleObj;
        }
        return InputMethodUtils.constructLocaleFromString(mSubtypeLocale);
    }

    /**
+45 −2
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;

import java.util.Locale;
import java.util.Objects;

public class InputMethodSubtypeTest extends InstrumentationTestCase {
@@ -47,6 +48,38 @@ public class InputMethodSubtypeTest extends InstrumentationTestCase {
                cloneViaParcel(cloneViaParcel(createDummySubtype(localeString))).hashCode());
    }

    @SmallTest
    public void testLocaleObj_locale() {
        final InputMethodSubtype usSubtype = createDummySubtype("en_US");
        Locale localeObject = usSubtype.getLocaleObject();
        assertEquals("en", localeObject.getLanguage());
        assertEquals("US", localeObject.getCountry());

        // The locale object should be cached.
        assertTrue(localeObject == usSubtype.getLocaleObject());
    }

    @SmallTest
    public void testLocaleObj_languageTag() {
        final InputMethodSubtype usSubtype = createDummySubtypeUsingLanguageTag("en-US");
        Locale localeObject = usSubtype.getLocaleObject();
        assertNotNull(localeObject);
        assertEquals("en", localeObject.getLanguage());
        assertEquals("US", localeObject.getCountry());

        // The locale object should be cached.
        assertTrue(localeObject == usSubtype.getLocaleObject());
    }

    @SmallTest
    public void testLocaleObj_emptyLocale() {
        final InputMethodSubtype emptyLocaleSubtype = createDummySubtype("");
        assertNull(emptyLocaleSubtype.getLocaleObject());
        // It should continue returning null when called multiple times.
        assertNull(emptyLocaleSubtype.getLocaleObject());
        assertNull(emptyLocaleSubtype.getLocaleObject());
    }

    @SmallTest
    public void testLocaleString() throws Exception {
        // The locale string in InputMethodSubtype has accepted an arbitrary text actually,
@@ -94,7 +127,7 @@ public class InputMethodSubtypeTest extends InstrumentationTestCase {
        }
    }

    private static final InputMethodSubtype createDummySubtype(final String locale) {
    private static InputMethodSubtype createDummySubtype(final String locale) {
        final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder();
        return builder.setSubtypeNameResId(0)
                .setSubtypeIconResId(0)
@@ -102,4 +135,14 @@ public class InputMethodSubtypeTest extends InstrumentationTestCase {
                .setIsAsciiCapable(true)
                .build();
    }

    private static InputMethodSubtype createDummySubtypeUsingLanguageTag(
            final String languageTag) {
        final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder();
        return builder.setSubtypeNameResId(0)
                .setSubtypeIconResId(0)
                .setLanguageTag(languageTag)
                .setIsAsciiCapable(true)
                .build();
    }
}
 No newline at end of file