Loading core/java/android/content/res/Configuration.java +19 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.content.ConfigurationProto.HARD_KEYBOARD_HIDDEN; import static android.content.ConfigurationProto.KEYBOARD; import static android.content.ConfigurationProto.KEYBOARD_HIDDEN; import static android.content.ConfigurationProto.LOCALES; import static android.content.ConfigurationProto.LOCALE_LIST; import static android.content.ConfigurationProto.MCC; import static android.content.ConfigurationProto.MNC; import static android.content.ConfigurationProto.NAVIGATION; Loading Loading @@ -1111,7 +1112,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration protoOutputStream.write(MCC, mcc); protoOutputStream.write(MNC, mnc); if (mLocaleList != null) { mLocaleList.writeToProto(protoOutputStream, LOCALES); protoOutputStream.write(LOCALE_LIST, mLocaleList.toLanguageTags()); } protoOutputStream.write(SCREEN_LAYOUT, screenLayout); protoOutputStream.write(COLOR_MODE, colorMode); Loading Loading @@ -1222,7 +1223,15 @@ public final class Configuration implements Parcelable, Comparable<Configuration .setVariant(variant) .setScript(script) .build(); // Log a WTF here if a repeated locale is found to avoid throwing an // exception in system server when LocaleList is created below final int inListIndex = list.indexOf(locale); if (inListIndex != -1) { Slog.wtf(TAG, "Repeated locale (" + list.get(inListIndex) + ")" + " found when trying to add: " + locale.toString()); } else { list.add(locale); } } catch (IllformedLocaleException e) { Slog.e(TAG, "readFromProto error building locale with: " + "language-" + language + ";country-" + country Loading Loading @@ -1275,6 +1284,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration case (int) WINDOW_CONFIGURATION: windowConfiguration.readFromProto(protoInputStream, WINDOW_CONFIGURATION); break; case (int) LOCALE_LIST: try { setLocales(LocaleList.forLanguageTags(protoInputStream.readString( LOCALE_LIST))); } catch (Exception e) { Slog.e(TAG, "error parsing locale list in configuration.", e); } break; } } } finally { Loading core/java/android/os/LocaleList.java +0 −22 Original line number Diff line number Diff line Loading @@ -21,9 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; import android.annotation.UnsupportedAppUsage; import android.content.LocaleProto; import android.icu.util.ULocale; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -142,26 +140,6 @@ public final class LocaleList implements Parcelable { dest.writeString(mStringRepresentation); } /** * Helper to write LocaleList to a protocol buffer output stream. Assumes the parent * protobuf has declared the locale as repeated. * * @param protoOutputStream Stream to write the locale to. * @param fieldId Field Id of the Locale as defined in the parent message. * @hide */ public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) { for (int i = 0; i < mList.length; i++) { final Locale locale = mList[i]; final long token = protoOutputStream.start(fieldId); protoOutputStream.write(LocaleProto.LANGUAGE, locale.getLanguage()); protoOutputStream.write(LocaleProto.COUNTRY, locale.getCountry()); protoOutputStream.write(LocaleProto.VARIANT, locale.getVariant()); protoOutputStream.write(LocaleProto.SCRIPT, locale.getScript()); protoOutputStream.end(token); } } /** * Retrieves a String representation of the language tags in this list. */ Loading core/proto/android/content/configuration.proto +2 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ message ConfigurationProto { optional float font_scale = 1; optional uint32 mcc = 2; optional uint32 mnc = 3 [ (.android.privacy).dest = DEST_EXPLICIT ]; repeated LocaleProto locales = 4; repeated LocaleProto locales = 4 [deprecated = true]; optional uint32 screen_layout = 5; optional uint32 color_mode = 6; optional uint32 touchscreen = 7; Loading @@ -48,6 +48,7 @@ message ConfigurationProto { optional uint32 smallest_screen_width_dp = 17; optional uint32 density_dpi = 18; optional .android.app.WindowConfigurationProto window_configuration = 19; optional string locale_list = 20; } /** Loading core/proto/android/content/locale.proto +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import "frameworks/base/core/proto/android/privacy.proto"; package android.content; message LocaleProto { option deprecated = true; option (.android.msg_privacy).dest = DEST_AUTOMATIC; optional string language = 1; Loading core/tests/coretests/src/android/content/res/ConfigurationTest.java +79 −0 Original line number Diff line number Diff line Loading @@ -16,16 +16,29 @@ package android.content.res; import android.content.Context; import android.os.LocaleList; import android.platform.test.annotations.Presubmit; import android.util.AtomicFile; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import com.android.server.usage.IntervalStatsProto; import junit.framework.TestCase; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Locale; /** * Build/install/run: bit FrameworksCoreTests:android.content.res.ConfigurationTest */ Loading Loading @@ -54,4 +67,70 @@ public class ConfigurationTest extends TestCase { config2.updateFrom(config); assertEquals(config2.screenLayout, Configuration.SCREENLAYOUT_COMPAT_NEEDED); } @Test public void testReadWriteProto() throws Exception { final Context context = InstrumentationRegistry.getTargetContext(); final File testDir = new File(context.getFilesDir(), "ConfigurationTest"); testDir.mkdirs(); final File proto = new File(testDir, "configs"); if (proto.exists()) { proto.delete(); } final Locale arabic = new Locale.Builder().setLocale(new Locale("ar", "AE")).build(); final Locale urdu = new Locale.Builder().setLocale(new Locale("ur", "IN")).build(); final Locale urduExtension = new Locale.Builder().setLocale(new Locale("ur", "IN")) .setExtension('u', "nu-latn").build(); Configuration write = new Configuration(); write.setLocales(new LocaleList(arabic, urdu, urduExtension)); writeToProto(proto, write); assertTrue("Failed to write configs to proto.", proto.exists()); final Configuration read = new Configuration(); try { readFromProto(proto, read); } finally { proto.delete(); } assertEquals("Missing locales in proto file written to disk.", read.getLocales().size(), write.getLocales().size()); assertTrue("Arabic locale not found in Configuration locale list.", read.getLocales().indexOf(arabic) != -1); assertTrue("Urdu locale not found in Configuration locale list.", read.getLocales().indexOf(urdu) != -1); assertTrue("Urdu locale with extensions not found in Configuration locale list.", read.getLocales().indexOf(urduExtension) != -1); } private void writeToProto(File f, Configuration config) throws Exception { final AtomicFile af = new AtomicFile(f); FileOutputStream fos = af.startWrite(); try { final ProtoOutputStream protoOut = new ProtoOutputStream(fos); final long token = protoOut.start(IntervalStatsProto.CONFIGURATIONS); config.writeToProto(protoOut, IntervalStatsProto.Configuration.CONFIG, false, false); protoOut.end(token); protoOut.flush(); af.finishWrite(fos); fos = null; } finally { af.failWrite(fos); } } private void readFromProto(File f, Configuration config) throws Exception { final AtomicFile afRead = new AtomicFile(f); try (FileInputStream in = afRead.openRead()) { final ProtoInputStream protoIn = new ProtoInputStream(in); if (protoIn.isNextField(IntervalStatsProto.CONFIGURATIONS)) { final long token = protoIn.start(IntervalStatsProto.CONFIGURATIONS); if (protoIn.isNextField(IntervalStatsProto.Configuration.CONFIG)) { config.readFromProto(protoIn, IntervalStatsProto.Configuration.CONFIG); protoIn.end(token); } } } } } Loading
core/java/android/content/res/Configuration.java +19 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.content.ConfigurationProto.HARD_KEYBOARD_HIDDEN; import static android.content.ConfigurationProto.KEYBOARD; import static android.content.ConfigurationProto.KEYBOARD_HIDDEN; import static android.content.ConfigurationProto.LOCALES; import static android.content.ConfigurationProto.LOCALE_LIST; import static android.content.ConfigurationProto.MCC; import static android.content.ConfigurationProto.MNC; import static android.content.ConfigurationProto.NAVIGATION; Loading Loading @@ -1111,7 +1112,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration protoOutputStream.write(MCC, mcc); protoOutputStream.write(MNC, mnc); if (mLocaleList != null) { mLocaleList.writeToProto(protoOutputStream, LOCALES); protoOutputStream.write(LOCALE_LIST, mLocaleList.toLanguageTags()); } protoOutputStream.write(SCREEN_LAYOUT, screenLayout); protoOutputStream.write(COLOR_MODE, colorMode); Loading Loading @@ -1222,7 +1223,15 @@ public final class Configuration implements Parcelable, Comparable<Configuration .setVariant(variant) .setScript(script) .build(); // Log a WTF here if a repeated locale is found to avoid throwing an // exception in system server when LocaleList is created below final int inListIndex = list.indexOf(locale); if (inListIndex != -1) { Slog.wtf(TAG, "Repeated locale (" + list.get(inListIndex) + ")" + " found when trying to add: " + locale.toString()); } else { list.add(locale); } } catch (IllformedLocaleException e) { Slog.e(TAG, "readFromProto error building locale with: " + "language-" + language + ";country-" + country Loading Loading @@ -1275,6 +1284,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration case (int) WINDOW_CONFIGURATION: windowConfiguration.readFromProto(protoInputStream, WINDOW_CONFIGURATION); break; case (int) LOCALE_LIST: try { setLocales(LocaleList.forLanguageTags(protoInputStream.readString( LOCALE_LIST))); } catch (Exception e) { Slog.e(TAG, "error parsing locale list in configuration.", e); } break; } } } finally { Loading
core/java/android/os/LocaleList.java +0 −22 Original line number Diff line number Diff line Loading @@ -21,9 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; import android.annotation.UnsupportedAppUsage; import android.content.LocaleProto; import android.icu.util.ULocale; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -142,26 +140,6 @@ public final class LocaleList implements Parcelable { dest.writeString(mStringRepresentation); } /** * Helper to write LocaleList to a protocol buffer output stream. Assumes the parent * protobuf has declared the locale as repeated. * * @param protoOutputStream Stream to write the locale to. * @param fieldId Field Id of the Locale as defined in the parent message. * @hide */ public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) { for (int i = 0; i < mList.length; i++) { final Locale locale = mList[i]; final long token = protoOutputStream.start(fieldId); protoOutputStream.write(LocaleProto.LANGUAGE, locale.getLanguage()); protoOutputStream.write(LocaleProto.COUNTRY, locale.getCountry()); protoOutputStream.write(LocaleProto.VARIANT, locale.getVariant()); protoOutputStream.write(LocaleProto.SCRIPT, locale.getScript()); protoOutputStream.end(token); } } /** * Retrieves a String representation of the language tags in this list. */ Loading
core/proto/android/content/configuration.proto +2 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ message ConfigurationProto { optional float font_scale = 1; optional uint32 mcc = 2; optional uint32 mnc = 3 [ (.android.privacy).dest = DEST_EXPLICIT ]; repeated LocaleProto locales = 4; repeated LocaleProto locales = 4 [deprecated = true]; optional uint32 screen_layout = 5; optional uint32 color_mode = 6; optional uint32 touchscreen = 7; Loading @@ -48,6 +48,7 @@ message ConfigurationProto { optional uint32 smallest_screen_width_dp = 17; optional uint32 density_dpi = 18; optional .android.app.WindowConfigurationProto window_configuration = 19; optional string locale_list = 20; } /** Loading
core/proto/android/content/locale.proto +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import "frameworks/base/core/proto/android/privacy.proto"; package android.content; message LocaleProto { option deprecated = true; option (.android.msg_privacy).dest = DEST_AUTOMATIC; optional string language = 1; Loading
core/tests/coretests/src/android/content/res/ConfigurationTest.java +79 −0 Original line number Diff line number Diff line Loading @@ -16,16 +16,29 @@ package android.content.res; import android.content.Context; import android.os.LocaleList; import android.platform.test.annotations.Presubmit; import android.util.AtomicFile; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import com.android.server.usage.IntervalStatsProto; import junit.framework.TestCase; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Locale; /** * Build/install/run: bit FrameworksCoreTests:android.content.res.ConfigurationTest */ Loading Loading @@ -54,4 +67,70 @@ public class ConfigurationTest extends TestCase { config2.updateFrom(config); assertEquals(config2.screenLayout, Configuration.SCREENLAYOUT_COMPAT_NEEDED); } @Test public void testReadWriteProto() throws Exception { final Context context = InstrumentationRegistry.getTargetContext(); final File testDir = new File(context.getFilesDir(), "ConfigurationTest"); testDir.mkdirs(); final File proto = new File(testDir, "configs"); if (proto.exists()) { proto.delete(); } final Locale arabic = new Locale.Builder().setLocale(new Locale("ar", "AE")).build(); final Locale urdu = new Locale.Builder().setLocale(new Locale("ur", "IN")).build(); final Locale urduExtension = new Locale.Builder().setLocale(new Locale("ur", "IN")) .setExtension('u', "nu-latn").build(); Configuration write = new Configuration(); write.setLocales(new LocaleList(arabic, urdu, urduExtension)); writeToProto(proto, write); assertTrue("Failed to write configs to proto.", proto.exists()); final Configuration read = new Configuration(); try { readFromProto(proto, read); } finally { proto.delete(); } assertEquals("Missing locales in proto file written to disk.", read.getLocales().size(), write.getLocales().size()); assertTrue("Arabic locale not found in Configuration locale list.", read.getLocales().indexOf(arabic) != -1); assertTrue("Urdu locale not found in Configuration locale list.", read.getLocales().indexOf(urdu) != -1); assertTrue("Urdu locale with extensions not found in Configuration locale list.", read.getLocales().indexOf(urduExtension) != -1); } private void writeToProto(File f, Configuration config) throws Exception { final AtomicFile af = new AtomicFile(f); FileOutputStream fos = af.startWrite(); try { final ProtoOutputStream protoOut = new ProtoOutputStream(fos); final long token = protoOut.start(IntervalStatsProto.CONFIGURATIONS); config.writeToProto(protoOut, IntervalStatsProto.Configuration.CONFIG, false, false); protoOut.end(token); protoOut.flush(); af.finishWrite(fos); fos = null; } finally { af.failWrite(fos); } } private void readFromProto(File f, Configuration config) throws Exception { final AtomicFile afRead = new AtomicFile(f); try (FileInputStream in = afRead.openRead()) { final ProtoInputStream protoIn = new ProtoInputStream(in); if (protoIn.isNextField(IntervalStatsProto.CONFIGURATIONS)) { final long token = protoIn.start(IntervalStatsProto.CONFIGURATIONS); if (protoIn.isNextField(IntervalStatsProto.Configuration.CONFIG)) { config.readFromProto(protoIn, IntervalStatsProto.Configuration.CONFIG); protoIn.end(token); } } } } }