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

Commit 2eabf05f authored by Adam Lesinski's avatar Adam Lesinski Committed by android-build-merger
Browse files

Merge "Improve performance of LocaleList with Resources" into nyc-dev am: bb26248b

am: 5e5e871f

* commit '5e5e871f':
  Improve performance of LocaleList with Resources

Change-Id: I86abeb2c4edfec2aad47ac3aec4d79017e2191c8
parents 4d1d0bcc 5e5e871f
Loading
Loading
Loading
Loading
+45 −19
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import android.os.DropBoxManager;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.LocaleList;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
@@ -130,6 +131,7 @@ import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.TimeZone;
@@ -4684,6 +4686,8 @@ public final class ActivityThread {
                    + config);

            mResourcesManager.applyConfigurationToResourcesLocked(config, compat);
            updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                    mResourcesManager.getConfiguration().getLocales());

            if (mConfiguration == null) {
                mConfiguration = new Configuration();
@@ -4987,6 +4991,24 @@ public final class ActivityThread {
        return insInfo.nativeLibraryDir;
    }

    /**
     * The LocaleList set for the app's resources may have been shuffled so that the preferred
     * Locale is at position 0. We must find the index of this preferred Locale in the
     * original LocaleList.
     */
    private void updateLocaleListFromAppContext(Context context, LocaleList newLocaleList) {
        final Locale bestLocale = context.getResources().getConfiguration().getLocales().get(0);
        final int newLocaleListSize = newLocaleList.size();
        for (int i = 0; i < newLocaleListSize; i++) {
            if (bestLocale.equals(newLocaleList.get(i))) {
                LocaleList.setDefault(newLocaleList, i);
                return;
            }
        }
        throw new AssertionError("chosen locale " + bestLocale + " must be present in LocaleList: "
                + newLocaleList.toLanguageTags());
    }

    private void handleBindApplication(AppBindData data) {
        // Register the UI Thread as a sensitive thread to the runtime.
        VMRuntime.registerSensitiveThread();
@@ -5045,6 +5067,24 @@ public final class ActivityThread {
         */
        TimeZone.setDefault(null);

        /*
         * Set the LocaleList. This may change once we create the App Context.
         */
        LocaleList.setDefault(data.config.getLocales());

        synchronized (mResourcesManager) {
            /*
             * Update the system configuration since its preloaded and might not
             * reflect configuration changes. The configuration object passed
             * in AppBindData can be safely assumed to be up to date
             */
            mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
            mCurDefaultDisplayDpi = data.config.densityDpi;

            // This calls mResourcesManager so keep it within the synchronized block.
            applyCompatConfiguration(mCurDefaultDisplayDpi);
        }

        data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);

        /**
@@ -5172,25 +5212,8 @@ public final class ActivityThread {
        }

        final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
        synchronized (mResourcesManager) {
            /*
             * Initialize the default locales in this process for the reasons we set the time zone.
             *
             * We do this through ResourcesManager, since we need to do locale negotiation.
             */
            mResourcesManager.setDefaultLocalesLocked(data.config.getLocales());

            /*
             * Update the system configuration since its preloaded and might not
             * reflect configuration changes. The configuration object passed
             * in AppBindData can be safely assumed to be up to date
             */
            mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
            mCurDefaultDisplayDpi = data.config.densityDpi;

            // This calls mResourcesManager so keep it within the synchronized block.
            applyCompatConfiguration(mCurDefaultDisplayDpi);
        }
        updateLocaleListFromAppContext(appContext,
                mResourcesManager.getConfiguration().getLocales());

        if (!Process.isIsolated() && !"android".equals(appContext.getPackageName())) {
            // This cache location probably points at credential-encrypted
@@ -5893,6 +5916,9 @@ public final class ActivityThread {
                    // immediately, because upon returning the view
                    // hierarchy will be informed about it.
                    if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
                        updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                                mResourcesManager.getConfiguration().getLocales());

                        // This actually changed the resources!  Tell
                        // everyone about it.
                        if (mPendingConfiguration == null ||
+4 −70
Original line number Diff line number Diff line
@@ -67,10 +67,6 @@ public class ResourcesManager {
                }
            };

    private String[] mSystemLocales = null;
    private final HashSet<String> mNonSystemLocales = new HashSet<>();
    private boolean mHasNonSystemLocales = false;

    /**
     * The global compatibility settings.
     */
@@ -479,12 +475,7 @@ public class ResourcesManager {
     */
    private Resources getOrCreateResources(@Nullable IBinder activityToken,
            @NonNull ResourcesKey key, @NonNull ClassLoader classLoader) {
        final boolean findSystemLocales;
        final boolean hasNonSystemLocales;
        synchronized (this) {
            findSystemLocales = (mSystemLocales == null || mSystemLocales.length == 0);
            hasNonSystemLocales = mHasNonSystemLocales;

            if (DEBUG) {
                Throwable here = new Throwable();
                here.fillInStackTrace();
@@ -538,24 +529,7 @@ public class ResourcesManager {
        // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
        ResourcesImpl resourcesImpl = createResourcesImpl(key);

        final String[] systemLocales = findSystemLocales
                ? AssetManager.getSystem().getLocales() : null;
        final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();

        // Avoid checking for non-pseudo-locales if we already know there were some from a previous
        // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
        // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
        // able to affect mHasNonSystemLocales.
        final boolean isPseudoLocalesOnly = hasNonSystemLocales ||
                LocaleList.isPseudoLocalesOnly(nonSystemLocales);

        synchronized (this) {
            if (mSystemLocales == null || mSystemLocales.length == 0) {
                mSystemLocales = systemLocales;
            }
            mNonSystemLocales.addAll(Arrays.asList(nonSystemLocales));
            mHasNonSystemLocales = mHasNonSystemLocales || !isPseudoLocalesOnly;

            ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key);
            if (existingResourcesImpl != null) {
                if (DEBUG) {
@@ -745,23 +719,6 @@ public class ResourcesManager {
        }
    }

    /* package */ void setDefaultLocalesLocked(@NonNull LocaleList locales) {
        if (mSystemLocales == null) {
            throw new RuntimeException("ResourcesManager is not ready to negotiate locales.");
        }
        final int bestLocale;
        if (mHasNonSystemLocales) {
            bestLocale = locales.getFirstMatchIndexWithEnglishSupported(mNonSystemLocales);
        } else {
            // We fallback to system locales if there was no locale specifically supported by the
            // assets. This is to properly support apps that only rely on the shared system assets
            // and don't need assets of their own.
            bestLocale = locales.getFirstMatchIndexWithEnglishSupported(mSystemLocales);
        }
        // set it for Java, this also affects newly created Resources
        LocaleList.setDefault(locales, bestLocale);
    }

    public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config,
                                                             @Nullable CompatibilityInfo compat) {
        try {
@@ -786,30 +743,7 @@ public class ResourcesManager {
                        | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
            }

            Configuration localeAdjustedConfig = config;
            final LocaleList configLocales = config.getLocales();
            if (!configLocales.isEmpty()) {
                setDefaultLocalesLocked(configLocales);
                final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
                if (adjustedLocales
                        != configLocales) { // has the same result as .equals() in this case
                    // The first locale in the list was not chosen. So we create a modified
                    // configuration with the adjusted locales (which moves the chosen locale to the
                    // front).
                    localeAdjustedConfig = new Configuration();
                    localeAdjustedConfig.setTo(config);
                    localeAdjustedConfig.setLocales(adjustedLocales);
                    // Also adjust the locale list in mResConfiguration, so that the Resources
                    // created later would have the same locale list.
                    if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
                        mResConfiguration.setLocales(adjustedLocales);
                        changes |= ActivityInfo.CONFIG_LOCALE;
                    }
                }
            }

            Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics,
                    compat);
            Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat);

            ApplicationPackageManager.configurationChanged();
            //Slog.i(TAG, "Configuration changed in " + currentPackageName());
@@ -821,7 +755,7 @@ public class ResourcesManager {
                ResourcesImpl r = mResourceImpls.valueAt(i).get();
                if (r != null) {
                    if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
                            + r + " config to: " + localeAdjustedConfig);
                            + r + " config to: " + config);
                    int displayId = key.mDisplayId;
                    boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
                    DisplayMetrics dm = defaultDisplayMetrics;
@@ -830,7 +764,7 @@ public class ResourcesManager {
                        if (tmpConfig == null) {
                            tmpConfig = new Configuration();
                        }
                        tmpConfig.setTo(localeAdjustedConfig);
                        tmpConfig.setTo(config);
                        if (!isDefaultDisplay) {
                            dm = getDisplayMetrics(displayId);
                            applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
@@ -840,7 +774,7 @@ public class ResourcesManager {
                        }
                        r.updateConfiguration(tmpConfig, dm, compat);
                    } else {
                        r.updateConfiguration(localeAdjustedConfig, dm, compat);
                        r.updateConfiguration(config, dm, compat);
                    }
                    //Slog.i(TAG, "Updated app resources " + v.getKey()
                    //        + " " + r + ": " + r.getConfiguration());
+1 −1
Original line number Diff line number Diff line
@@ -1446,7 +1446,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
     *
     * @return The locale list.
     */
    public LocaleList getLocales() {
    public @NonNull LocaleList getLocales() {
        fixUpLocaleList();
        return mLocaleList;
    }
+28 −3
Original line number Diff line number Diff line
@@ -330,18 +330,43 @@ public class ResourcesImpl {
                // doing the conversion here.  This impl should be okay because
                // we make sure to return a compatible display in the places
                // where there are public APIs to retrieve the display...  but
                // it would be cleaner and more maintainble to just be
                // it would be cleaner and more maintainable to just be
                // consistently dealing with a compatible display everywhere in
                // the framework.
                mCompatibilityInfo.applyToDisplayMetrics(mMetrics);

                final @Config int configChanges = calcConfigChanges(config);

                // If even after the update there are no Locales set, grab the default locales.
                LocaleList locales = mConfiguration.getLocales();
                if (locales.isEmpty()) {
                    locales = LocaleList.getAdjustedDefault();
                    locales = LocaleList.getDefault();
                    mConfiguration.setLocales(locales);
                }

                if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) {
                    if (locales.size() > 1) {
                        // The LocaleList has changed. We must query the AssetManager's available
                        // Locales and figure out the best matching Locale in the new LocaleList.
                        String[] availableLocales = mAssets.getNonSystemLocales();
                        if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
                            // No app defined locales, so grab the system locales.
                            availableLocales = mAssets.getLocales();
                            if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
                                availableLocales = null;
                            }
                        }

                        if (availableLocales != null) {
                            final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
                                    availableLocales);
                            if (bestLocale != null && bestLocale != locales.get(0)) {
                                mConfiguration.setLocales(new LocaleList(bestLocale, locales));
                            }
                        }
                    }
                }

                if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
                    mMetrics.densityDpi = mConfiguration.densityDpi;
                    mMetrics.density =
@@ -370,7 +395,7 @@ public class ResourcesImpl {
                }

                mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
                        adjustLanguageTag(locales.get(0).toLanguageTag()),
                        adjustLanguageTag(mConfiguration.getLocales().get(0).toLanguageTag()),
                        mConfiguration.orientation,
                        mConfiguration.touchscreen,
                        mConfiguration.densityDpi, mConfiguration.keyboard,
+13 −1
Original line number Diff line number Diff line
@@ -408,6 +408,14 @@ public final class LocaleList implements Parcelable {
                false /* assume English is not supported */);
    }

    /**
     * {@hide}
     */
    public int getFirstMatchIndex(String[] supportedLocales) {
        return computeFirstMatchIndex(Arrays.asList(supportedLocales),
                false /* assume English is not supported */);
    }

    /**
     * Same as getFirstMatch(), but with English assumed to be supported, even if it's not.
     * {@hide}
@@ -437,7 +445,11 @@ public final class LocaleList implements Parcelable {
     * Assumes that there is no repetition in the input.
     * {@hide}
     */
    public static boolean isPseudoLocalesOnly(String[] supportedLocales) {
    public static boolean isPseudoLocalesOnly(@Nullable String[] supportedLocales) {
        if (supportedLocales == null) {
            return true;
        }

        if (supportedLocales.length > NUM_PSEUDO_LOCALES + 1) {
            // This is for optimization. Since there's no repetition in the input, if we have more
            // than the number of pseudo-locales plus one for the empty string, it's guaranteed
Loading