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

Commit cdc56736 authored by Roozbeh Pournader's avatar Roozbeh Pournader Committed by Android (Google) Code Review
Browse files

Merge "Make res.Configuration support locale lists."

parents 26637cb3 b46fdd42
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -9663,12 +9663,14 @@ package android.content.res {
    method public int diff(android.content.res.Configuration);
    method public boolean equals(android.content.res.Configuration);
    method public int getLayoutDirection();
    method public android.util.LocaleList getLocales();
    method public boolean isLayoutSizeAtLeast(int);
    method public boolean isScreenRound();
    method public static boolean needNewResources(int, int);
    method public void readFromParcel(android.os.Parcel);
    method public void setLayoutDirection(java.util.Locale);
    method public void setLocale(java.util.Locale);
    method public void setLocales(android.util.LocaleList);
    method public void setTo(android.content.res.Configuration);
    method public void setToDefaults();
    method public int updateFrom(android.content.res.Configuration);
@@ -9742,7 +9744,7 @@ package android.content.res {
    field public int hardKeyboardHidden;
    field public int keyboard;
    field public int keyboardHidden;
    field public java.util.Locale locale;
    field public deprecated java.util.Locale locale;
    field public int mcc;
    field public int mnc;
    field public int navigation;
@@ -34201,11 +34203,15 @@ package android.util {
  public final class LocaleList {
    ctor public LocaleList();
    ctor public LocaleList(java.util.Locale);
    ctor public LocaleList(java.util.Locale[]);
    method public static android.util.LocaleList forLanguageTags(java.lang.String);
    method public java.util.Locale get(int);
    method public static android.util.LocaleList getEmptyLocaleList();
    method public java.util.Locale getPrimary();
    method public boolean isEmpty();
    method public int size();
    method public java.lang.String toLanguageTags();
  }
  public final class Log {
+7 −1
Original line number Diff line number Diff line
@@ -10000,12 +10000,14 @@ package android.content.res {
    method public int diff(android.content.res.Configuration);
    method public boolean equals(android.content.res.Configuration);
    method public int getLayoutDirection();
    method public android.util.LocaleList getLocales();
    method public boolean isLayoutSizeAtLeast(int);
    method public boolean isScreenRound();
    method public static boolean needNewResources(int, int);
    method public void readFromParcel(android.os.Parcel);
    method public void setLayoutDirection(java.util.Locale);
    method public void setLocale(java.util.Locale);
    method public void setLocales(android.util.LocaleList);
    method public void setTo(android.content.res.Configuration);
    method public void setToDefaults();
    method public int updateFrom(android.content.res.Configuration);
@@ -10079,7 +10081,7 @@ package android.content.res {
    field public int hardKeyboardHidden;
    field public int keyboard;
    field public int keyboardHidden;
    field public java.util.Locale locale;
    field public deprecated java.util.Locale locale;
    field public int mcc;
    field public int mnc;
    field public int navigation;
@@ -36495,11 +36497,15 @@ package android.util {
  public final class LocaleList {
    ctor public LocaleList();
    ctor public LocaleList(java.util.Locale);
    ctor public LocaleList(java.util.Locale[]);
    method public static android.util.LocaleList forLanguageTags(java.lang.String);
    method public java.util.Locale get(int);
    method public static android.util.LocaleList getEmptyLocaleList();
    method public java.util.Locale getPrimary();
    method public boolean isEmpty();
    method public int size();
    method public java.lang.String toLanguageTags();
  }
  public final class Log {
+146 −64
Original line number Diff line number Diff line
@@ -22,11 +22,13 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.LocaleList;
import android.view.View;

import java.io.IOException;
@@ -36,7 +38,7 @@ import java.util.Locale;
/**
 * This class describes all device configuration information that can
 * impact the resources the application retrieves.  This includes both
 * user-specified configuration options (locale and scaling) as well
 * user-specified configuration options (locale list and scaling) as well
 * as device configurations (such as input modes, screen size and screen orientation).
 * <p>You can acquire this object from {@link Resources}, using {@link
 * Resources#getConfiguration}. Thus, from an activity, you can get it by chaining the request
@@ -78,8 +80,13 @@ public final class Configuration implements Parcelable, Comparable<Configuration
     * Current user preference for the locale, corresponding to
     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
     * resource qualifier.
     *
     * @deprecated Do not set or read this directly. Use {@link #getLocales()} and
     * {@link #setLocales(LocaleList)}.
     */
    public Locale locale;
    @Deprecated public Locale locale;

    private LocaleList mLocaleList;

    /**
     * Locale should persist on setting.  This is hidden because it is really
@@ -648,6 +655,15 @@ public final class Configuration implements Parcelable, Comparable<Configuration
        setTo(o);
    }

    /* This brings mLocaleList in sync with locale in case a user of the older API who doesn't know
     * about setLocales() has changed locale directly. */
    private void fixUpLocaleList() {
        if ((locale == null && !mLocaleList.isEmpty()) ||
                (locale != null && !locale.equals(mLocaleList.getPrimary()))) {
            mLocaleList = new LocaleList(locale);
        }
    }

    public void setTo(Configuration o) {
        fontScale = o.fontScale;
        mcc = o.mcc;
@@ -655,6 +671,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
        if (o.locale != null) {
            locale = (Locale) o.locale.clone();
        }
        o.fixUpLocaleList();
        mLocaleList = o.mLocaleList;
        userSetLocale = o.userSetLocale;
        touchscreen = o.touchscreen;
        keyboard = o.keyboard;
@@ -692,11 +710,12 @@ public final class Configuration implements Parcelable, Comparable<Configuration
        } else {
            sb.append("?mnc");
        }
        if (locale != null) {
        fixUpLocaleList();
        if (!mLocaleList.isEmpty()) {
            sb.append(" ");
            sb.append(locale);
            sb.append(mLocaleList);
        } else {
            sb.append(" ?locale");
            sb.append(" ?localeList");
        }
        int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK);
        switch (layoutDir) {
@@ -819,6 +838,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
    public void setToDefaults() {
        fontScale = 1;
        mcc = mnc = 0;
        mLocaleList = LocaleList.getEmptyLocaleList();
        locale = null;
        userSetLocale = false;
        touchscreen = TOUCHSCREEN_UNDEFINED;
@@ -864,17 +884,21 @@ public final class Configuration implements Parcelable, Comparable<Configuration
            changed |= ActivityInfo.CONFIG_MNC;
            mnc = delta.mnc;
        }
        if (delta.locale != null
                && (locale == null || !locale.equals(delta.locale))) {
        fixUpLocaleList();
        delta.fixUpLocaleList();
        if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) {
            changed |= ActivityInfo.CONFIG_LOCALE;
            locale = delta.locale != null
                    ? (Locale) delta.locale.clone() : null;
            mLocaleList = delta.mLocaleList;
            // delta.locale can't be null, since delta.mLocaleList is not empty.
            if (!delta.locale.equals(locale)) {
                locale = (Locale) delta.locale.clone();
                // If locale has changed, then layout direction is also changed ...
                changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
                // ... and we need to update the layout direction (represented by the first
                // 2 most significant bits in screenLayout).
                setLayoutDirection(locale);
            }
        }
        final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
        if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED &&
                deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) {
@@ -1023,8 +1047,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
        if (delta.mnc != 0 && mnc != delta.mnc) {
            changed |= ActivityInfo.CONFIG_MNC;
        }
        if (delta.locale != null
                && (locale == null || !locale.equals(delta.locale))) {
        fixUpLocaleList();
        delta.fixUpLocaleList();
        if (!mLocaleList.equals(delta.mLocaleList)) {
            changed |= ActivityInfo.CONFIG_LOCALE;
            changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
        }
@@ -1146,14 +1171,15 @@ public final class Configuration implements Parcelable, Comparable<Configuration
        dest.writeFloat(fontScale);
        dest.writeInt(mcc);
        dest.writeInt(mnc);
        if (locale == null) {
            dest.writeInt(0);
        } else {
            dest.writeInt(1);
            dest.writeString(locale.getLanguage());
            dest.writeString(locale.getCountry());
            dest.writeString(locale.getVariant());

        fixUpLocaleList();
        final int localeListSize = mLocaleList.size();
        dest.writeInt(localeListSize);
        for (int i = 0; i < localeListSize; ++i) {
            final Locale l = mLocaleList.get(i);
            dest.writeString(l.toLanguageTag());
        }

        if(userSetLocale) {
            dest.writeInt(1);
        } else {
@@ -1182,10 +1208,15 @@ public final class Configuration implements Parcelable, Comparable<Configuration
        fontScale = source.readFloat();
        mcc = source.readInt();
        mnc = source.readInt();
        if (source.readInt() != 0) {
            locale = new Locale(source.readString(), source.readString(),
                    source.readString());

        final int localeListSize = source.readInt();
        final Locale[] localeArray = new Locale[localeListSize];
        for (int i = 0; i < localeListSize; ++i) {
            localeArray[i] = Locale.forLanguageTag(source.readString());
        }
        mLocaleList = new LocaleList(localeArray);
        locale = mLocaleList.getPrimary();

        userSetLocale = (source.readInt()==1);
        touchscreen = source.readInt();
        keyboard = source.readInt();
@@ -1234,18 +1265,33 @@ public final class Configuration implements Parcelable, Comparable<Configuration
        if (n != 0) return n;
        n = this.mnc - that.mnc;
        if (n != 0) return n;
        if (this.locale == null) {
            if (that.locale != null) return 1;
        } else if (that.locale == null) {

        fixUpLocaleList();
        that.fixUpLocaleList();
        // for backward compatibility, we consider an empty locale list to be greater
        // than any non-empty locale list.
        if (this.mLocaleList.isEmpty()) {
            if (!that.mLocaleList.isEmpty()) return 1;
        } else if (that.mLocaleList.isEmpty()) {
            return -1;
        } else {
            n = this.locale.getLanguage().compareTo(that.locale.getLanguage());
            final int minSize = Math.min(this.mLocaleList.size(), that.mLocaleList.size());
            for (int i = 0; i < minSize; ++i) {
                final Locale thisLocale = this.mLocaleList.get(i);
                final Locale thatLocale = that.mLocaleList.get(i);
                n = thisLocale.getLanguage().compareTo(thatLocale.getLanguage());
                if (n != 0) return n;
            n = this.locale.getCountry().compareTo(that.locale.getCountry());
                n = thisLocale.getCountry().compareTo(thatLocale.getCountry());
                if (n != 0) return n;
            n = this.locale.getVariant().compareTo(that.locale.getVariant());
                n = thisLocale.getVariant().compareTo(thatLocale.getVariant());
                if (n != 0) return n;
                n = thisLocale.toLanguageTag().compareTo(thatLocale.toLanguageTag());
                if (n != 0) return n;
            }
            n = this.mLocaleList.size() - that.mLocaleList.size();
            if (n != 0) return n;
        }

        n = this.touchscreen - that.touchscreen;
        if (n != 0) return n;
        n = this.keyboard - that.keyboard;
@@ -1294,7 +1340,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
        result = 31 * result + Float.floatToIntBits(fontScale);
        result = 31 * result + mcc;
        result = 31 * result + mnc;
        result = 31 * result + (locale != null ? locale.hashCode() : 0);
        result = 31 * result + mLocaleList.hashCode();
        result = 31 * result + touchscreen;
        result = 31 * result + keyboard;
        result = 31 * result + keyboardHidden;
@@ -1312,16 +1358,49 @@ public final class Configuration implements Parcelable, Comparable<Configuration
    }

    /**
     * Set the locale. This is the preferred way for setting up the locale (instead of using the
     * direct accessor). This will also set the layout direction according to the locale.
     * Get the locale list. This is the preferred way for getting the locales (instead of using
     * the direct accessor to {@link #locale}, which would only provide the primary locale).
     *
     * @param loc The locale. Can be null.
     * @return The locale list.
     */
    public void setLocale(Locale loc) {
        locale = loc;
    public LocaleList getLocales() {
        fixUpLocaleList();
        return mLocaleList;
    }

    /**
     * Set the locale list. This is the preferred way for setting up the locales (instead of using
     * the direct accessor or {@link #setLocale(Locale)}). This will also set the layout direction
     * according to the first locale in the list.
     *
     * Note that the layout direction will always come from the first locale in the locale list,
     * even if the locale is not supported by the resources (the resources may only support
     * another locale further down the list which has a different direction).
     *
     * @param locales The locale list. If null, an empty LocaleList will be assigned.
     */
    public void setLocales(@Nullable LocaleList locales) {
        mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales;
        locale = mLocaleList.getPrimary();
        setLayoutDirection(locale);
    }

    /**
     * Set the locale list to a list of just one locale. This will also set the layout direction
     * according to the locale.
     *
     * Note that after this is run, calling <code>.equals()</code> on the input locale and the
     * {@link #locale} attribute would return <code>true</code> if they are not null, but there is
     * no guarantee that they would be the same object.
     *
     * See also the note about layout direction in {@link #setLocales(LocaleList)}.
     *
     * @param loc The locale. Can be null.
     */
    public void setLocale(@Nullable Locale loc) {
        setLocales(new LocaleList(loc));
    }

    /**
     * Return the layout direction. Will be either {@link View#LAYOUT_DIRECTION_LTR} or
     * {@link View#LAYOUT_DIRECTION_RTL}.
@@ -1335,19 +1414,19 @@ public final class Configuration implements Parcelable, Comparable<Configuration
    }

    /**
     * Set the layout direction from the Locale.
     * Set the layout direction from a Locale.
     *
     * @param locale The Locale. If null will set the layout direction to
     * @param loc The Locale. If null will set the layout direction to
     * {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction
     * corresponding to the Locale.
     *
     * @see View#LAYOUT_DIRECTION_LTR
     * @see View#LAYOUT_DIRECTION_RTL
     */
    public void setLayoutDirection(Locale locale) {
    public void setLayoutDirection(Locale loc) {
        // There is a "1" difference between the configuration values for
        // layout direction and View constants for layout direction, just add "1".
        final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(locale);
        final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(loc);
        screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)|
                (layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT);
    }
@@ -1370,21 +1449,21 @@ public final class Configuration implements Parcelable, Comparable<Configuration
     *
     * @hide
     */
    public static String localeToResourceQualifier(Locale locale) {
    public static String localeToResourceQualifier(Locale loc) {
        StringBuilder sb = new StringBuilder();
        boolean l = (locale.getLanguage().length() != 0);
        boolean c = (locale.getCountry().length() != 0);
        boolean s = (locale.getScript().length() != 0);
        boolean v = (locale.getVariant().length() != 0);

        boolean l = (loc.getLanguage().length() != 0);
        boolean c = (loc.getCountry().length() != 0);
        boolean s = (loc.getScript().length() != 0);
        boolean v = (loc.getVariant().length() != 0);
        // TODO: take script and extensions into account
        if (l) {
            sb.append(locale.getLanguage());
            sb.append(loc.getLanguage());
            if (c) {
                sb.append("-r").append(locale.getCountry());
                sb.append("-r").append(loc.getCountry());
                if (s) {
                    sb.append("-s").append(locale.getScript());
                    sb.append("-s").append(loc.getScript());
                    if (v) {
                        sb.append("-v").append(locale.getVariant());
                        sb.append("-v").append(loc.getVariant());
                    }
                }
            }
@@ -1409,6 +1488,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
            }
        }

        // TODO: send the whole locale list
        if (config.locale != null && !config.locale.getLanguage().isEmpty()) {
            parts.add(localeToResourceQualifier(config.locale));
        }
@@ -1646,8 +1726,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
            delta.mnc = change.mnc;
        }

        if ((base.locale == null && change.locale != null) ||
                (base.locale != null && !base.locale.equals(change.locale)))  {
        base.fixUpLocaleList();
        change.fixUpLocaleList();
        if (!base.mLocaleList.equals(change.mLocaleList))  {
            delta.mLocaleList = change.mLocaleList;
            delta.locale = change.locale;
        }

@@ -1724,7 +1806,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
    private static final String XML_ATTR_FONT_SCALE = "fs";
    private static final String XML_ATTR_MCC = "mcc";
    private static final String XML_ATTR_MNC = "mnc";
    private static final String XML_ATTR_LOCALE = "locale";
    private static final String XML_ATTR_LOCALES = "locales";
    private static final String XML_ATTR_TOUCHSCREEN = "touch";
    private static final String XML_ATTR_KEYBOARD = "key";
    private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid";
@@ -1754,10 +1836,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
        configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0);
        configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0);

        final String localeStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALE);
        if (localeStr != null) {
            configOut.locale = Locale.forLanguageTag(localeStr);
        }
        final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES);
        configOut.mLocaleList = LocaleList.forLanguageTags(localesStr);
        configOut.locale = configOut.mLocaleList.getPrimary();

        configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN,
                TOUCHSCREEN_UNDEFINED);
@@ -1807,8 +1888,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
        if (config.mnc != 0) {
            XmlUtils.writeIntAttribute(xml, XML_ATTR_MNC, config.mnc);
        }
        if (config.locale != null) {
            XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALE, config.locale.toLanguageTag());
        config.fixUpLocaleList();
        if (!config.mLocaleList.isEmpty()) {
           XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALES, config.mLocaleList.toLanguageTags());
        }
        if (config.touchscreen != TOUCHSCREEN_UNDEFINED) {
            XmlUtils.writeIntAttribute(xml, XML_ATTR_TOUCHSCREEN, config.touchscreen);
+87 −2
Original line number Diff line number Diff line
@@ -23,8 +23,8 @@ import java.util.Locale;

// TODO: We don't except too many LocaleLists to exist at the same time, and
// we need access to the data at native level, so we should pass the data
// down to the native level, create a mapt of every list seen there, take a
// pointer back, and just keep that pointed in the Java-level object, so
// down to the native level, create a map of every list seen there, take a
// pointer back, and just keep that pointer in the Java-level object, so
// things could be copied very quickly.

/**
@@ -34,6 +34,7 @@ import java.util.Locale;
public final class LocaleList {
    private final Locale[] mList;
    private static final Locale[] sEmptyList = new Locale[0];
    private static final LocaleList sEmptyLocaleList = new LocaleList();

    public Locale get(int location) {
        return location < mList.length ? mList[location] : null;
@@ -51,10 +52,77 @@ public final class LocaleList {
        return mList.length;
    }

    @Override
    public boolean equals(Object other) {
        if (other == this)
            return true;
        if (!(other instanceof LocaleList))
            return false;
        final Locale[] otherList = ((LocaleList) other).mList;
        if (mList.length != otherList.length)
            return false;
        for (int i = 0; i < mList.length; ++i) {
            if (!mList[i].equals(otherList[i]))
                return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int result = 1;
        for (int i = 0; i < mList.length; ++i) {
            result = 31 * result + mList[i].hashCode();
        }
        return result;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < mList.length; ++i) {
            sb.append(mList[i]);
            if (i < mList.length - 1) {
                sb.append(',');
            }
        }
        sb.append("]");
        return sb.toString();
    }

    public String toLanguageTags() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < mList.length; ++i) {
            sb.append(mList[i].toLanguageTag());
            if (i < mList.length - 1) {
                sb.append(',');
            }
        }
        return sb.toString();
    }

    /**
     * It is almost always better to call {@link #getEmptyLocaleList()} instead which returns
     * a pre-constructed empty locale list.
     */
    public LocaleList() {
        mList = sEmptyList;
    }

    /**
     * @throws NullPointerException if any of the input locales is <code>null</code>.
     * @throws IllegalArgumentException if any of the input locales repeat.
     */
    public LocaleList(@Nullable Locale locale) {
        if (locale == null) {
            mList = sEmptyList;
        } else {
            mList = new Locale[1];
            mList[0] = (Locale) locale.clone();
        }
    }

    /**
     * @throws NullPointerException if any of the input locales is <code>null</code>.
     * @throws IllegalArgumentException if any of the input locales repeat.
@@ -79,4 +147,21 @@ public final class LocaleList {
            mList = localeList;
        }
    }

    public static LocaleList getEmptyLocaleList() {
        return sEmptyLocaleList;
    }

    public static LocaleList forLanguageTags(@Nullable String list) {
        if (list == null || list.equals("")) {
            return getEmptyLocaleList();
        } else {
            final String[] tags = list.split(",");
            final Locale[] localeArray = new Locale[tags.length];
            for (int i = 0; i < localeArray.length; ++i) {
                localeArray[i] = Locale.forLanguageTag(tags[i]);
            }
            return new LocaleList(localeArray);
        }
    }
}