Merge "Regenerate date for CLDR-18367" into main am: 0eabc9f94e

Original change: https://android-review.googlesource.com/c/platform/external/icu/+/3556503

Change-Id: I340ff836f4b10c649d1ba4b0eaea17355e01bf2f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index 93f2e36..bc47e01 100644
--- a/Android.bp
+++ b/Android.bp
@@ -87,7 +87,8 @@
 aconfig_declarations {
     name: "icu_aconfig_flags",
     package: "com.android.icu",
-    container: "system",
+    container: "com.android.i18n",
+    exportable: true,
     srcs: [
         "icu.aconfig",
     ],
diff --git a/android_icu4j/Android.bp b/android_icu4j/Android.bp
index fd6edc4..9cd4d77 100644
--- a/android_icu4j/Android.bp
+++ b/android_icu4j/Android.bp
@@ -97,18 +97,18 @@
     name: "core-repackaged-icu4j",
     installable: false,
     srcs: [":android_icu4j_repackaged_src_files"],
+    // The resource files are generated in the downstream branch master-icu-dev.
+    java_resource_dirs: ["resources"],
     libs: [
         "unsupportedappusage",
         // Need framework-api-annotations-lib for @FlaggedApi.
         // Put framework-api-annotations into libs to avoid exposing the definition of framework's
         // annotations from ICU (wrong place) instead of framework (correct place).
         "framework-annotations-lib",
-        // We only need the aconfig library for @FlaggedApi. We can move it to static_libs
-        // if we need it for flagging features in the future.
+    ],
+    static_libs: [
         "icu_aconfig_flags_lib",
     ],
-    // The resource files are generated in the downstream branch master-icu-dev.
-    java_resource_dirs: ["resources"],
 
     sdk_version: "none",
     system_modules: "art-module-public-api-stubs-system-modules",
@@ -154,6 +154,9 @@
     installable: true,
     hostdex: false,
 
+    libs: [
+        "framework-annotations-lib",
+    ],
     static_libs: ["core-repackaged-icu4j"],
 
     // It is important that core-icu4j is restricted to only use stable APIs from the ART module
@@ -442,6 +445,10 @@
         "--show-single-annotation libcore.api.CorePlatformApi ",
     ],
 
+    libs: [
+        "icu_aconfig_flags_lib",
+    ],
+
     // Don't copy any output files to the dist.
     no_dist: true,
 
@@ -543,6 +550,17 @@
         "src/main/tests/**/*.java",
         "testing/src/**/*.java",
     ],
+    libs: [
+        "icu_aconfig_flags_lib",
+        "telephony-common",
+        "telephony_flags_core_java_lib",
+    ],
+    static_libs: [
+        "flag-junit",
+        "junit",
+        "platform-parametric-runner-lib",
+        "platform-test-annotations",
+    ],
 }
 
 // Equivalent to android-icu4j-tests, excluding the tests under testing/.
diff --git a/android_icu4j/api/legacy_platform/current.txt b/android_icu4j/api/legacy_platform/current.txt
index ca3fafb..6b178a6 100644
--- a/android_icu4j/api/legacy_platform/current.txt
+++ b/android_icu4j/api/legacy_platform/current.txt
@@ -70,6 +70,12 @@
     method public static com.android.i18n.timezone.DebugInfo getDebugInfo();
   }
 
+  @FlaggedApi("com.android.icu.telephony_lookup_mcc_extension") public final class MobileCountries {
+    method @NonNull public java.util.Set<java.lang.String> getCountryIsoCodes();
+    method @NonNull public String getDefaultCountryIsoCode();
+    method @NonNull public String getMcc();
+  }
+
   public final class TelephonyLookup {
     method public static com.android.i18n.timezone.TelephonyLookup createInstance(String) throws java.io.IOException;
     method public static com.android.i18n.timezone.TelephonyLookup getInstance();
@@ -84,6 +90,7 @@
   }
 
   public final class TelephonyNetworkFinder {
+    method @FlaggedApi("com.android.icu.telephony_lookup_mcc_extension") @Nullable public com.android.i18n.timezone.MobileCountries findCountriesByMcc(@NonNull String);
     method public com.android.i18n.timezone.TelephonyNetwork findNetworkByMccMnc(String, String);
   }
 
diff --git a/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/MobileCountries.java b/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/MobileCountries.java
new file mode 100644
index 0000000..a760cf3
--- /dev/null
+++ b/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/MobileCountries.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.i18n.timezone;
+
+import static java.util.stream.Collectors.toUnmodifiableSet;
+
+import android.annotation.NonNull;
+
+import com.android.icu.Flags;
+
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Information about the countries where an MCC operates.
+ *
+ * @hide
+ */
+@libcore.api.CorePlatformApi
+@android.annotation.FlaggedApi(Flags.FLAG_TELEPHONY_LOOKUP_MCC_EXTENSION)
+public final class MobileCountries {
+
+    private final String mcc;
+    private final String defaultCountryIsoCode;
+    private final Set<String> countryIsoCodes;
+
+    public static MobileCountries create(String mcc, Set<String> countryIsoCodes,
+            String defaultCountryIsoCode) {
+        Objects.requireNonNull(mcc);
+        Objects.requireNonNull(countryIsoCodes);
+        Objects.requireNonNull(defaultCountryIsoCode);
+
+        Set<String> normalizedCountryIsos = countryIsoCodes.stream()
+                .map(XmlUtils::normalizeCountryIso)
+                .collect(toUnmodifiableSet());
+        return new MobileCountries(Objects.requireNonNull(mcc), normalizedCountryIsos,
+                XmlUtils.normalizeCountryIso(defaultCountryIsoCode));
+    }
+
+    private MobileCountries(String mcc, Set<String> countryIsoCodes,
+            String defaultCountryIsoCode) {
+        if (!countryIsoCodes.contains(Objects.requireNonNull(defaultCountryIsoCode))) {
+            throw new IllegalArgumentException(
+                    "The default country ISO code was not found in the set of country ISO codes");
+        }
+        this.mcc = Objects.requireNonNull(mcc);
+        this.countryIsoCodes = Objects.requireNonNull(countryIsoCodes);
+        this.defaultCountryIsoCode = Objects.requireNonNull(defaultCountryIsoCode);
+    }
+
+    /**
+     * Returns the MCC of the network.
+     */
+    @libcore.api.CorePlatformApi
+    @NonNull
+    public String getMcc() {
+        return mcc;
+    }
+
+    /**
+     * Returns the countries in which this MCC is used as an ISO 3166 alpha-2 (lower case).
+     */
+    @libcore.api.CorePlatformApi
+    @NonNull
+    public Set<String> getCountryIsoCodes() {
+        return countryIsoCodes;
+    }
+
+    /**
+     * Returns the default country for this MCC as an ISO 3166 alpha-2 (lower case).
+     */
+    @libcore.api.CorePlatformApi
+    @NonNull
+    public String getDefaultCountryIsoCode() {
+        return defaultCountryIsoCode;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o instanceof MobileCountries that) {
+            return mcc.equals(that.mcc) && countryIsoCodes.equals(that.countryIsoCodes)
+                    && defaultCountryIsoCode.equals(that.defaultCountryIsoCode);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mcc, countryIsoCodes, defaultCountryIsoCode);
+    }
+
+    @Override
+    public String toString() {
+        return "MobileCountries{"
+                + "mcc=" + mcc
+                + ", countryIsoCodes='" + countryIsoCodes
+                + ", defaultCountryIsoCode='" + defaultCountryIsoCode + '\''
+                + '}';
+    }
+}
diff --git a/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TelephonyLookup.java b/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TelephonyLookup.java
index 826ee67..f910524 100644
--- a/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TelephonyLookup.java
+++ b/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TelephonyLookup.java
@@ -17,6 +17,7 @@
 package com.android.i18n.timezone;
 
 import static com.android.i18n.timezone.XmlUtils.checkOnEndTag;
+import static com.android.i18n.timezone.XmlUtils.consumeText;
 import static com.android.i18n.timezone.XmlUtils.consumeUntilEndTag;
 import static com.android.i18n.timezone.XmlUtils.findNextStartTagOrEndTagNoRecurse;
 import static com.android.i18n.timezone.XmlUtils.findNextStartTagOrThrowNoRecurse;
@@ -25,6 +26,7 @@
 import com.android.i18n.timezone.TelephonyNetwork.MccMnc;
 import com.android.i18n.timezone.XmlUtils.ReaderSupplier;
 import com.android.i18n.util.Log;
+import com.android.icu.Flags;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -65,6 +67,13 @@
     // This is the ISO 3166 alpha-2 code (in lower case).
     private static final String COUNTRY_ISO_CODE_ATTRIBUTE = "country";
 
+    // <mobile_countries>
+    private static final String MOBILE_COUNTRIES_ELEMENT = "mobile_countries";
+
+    // <mobile_country mcc="123" [default="gu"]>
+    private static final String MOBILE_COUNTRY_ELEMENT = "mobile_country";
+    private static final String DEFAULT_ATTRIBUTE = "default";
+
     private static TelephonyLookup instance;
 
     private final ReaderSupplier xmlSource;
@@ -112,7 +121,12 @@
 
         Log.e("No valid file found in set: " + Arrays.toString(telephonyLookupFilePaths)
                 + " Printing exceptions and falling back to empty map.", lastException);
-        return createInstanceForTests("<telephony_lookup><networks /></telephony_lookup>");
+        return createInstanceFromString("""
+                             <telephony_lookup>
+                              <networks/>
+                              <mobile_countries/>
+                             </telephony_lookup>
+                             """);
     }
 
     /**
@@ -128,7 +142,7 @@
 
     /** Used to create an instance using an in-memory XML String instead of a file. */
     // VisibleForTesting
-    public static TelephonyLookup createInstanceForTests(String xml) {
+    public static TelephonyLookup createInstanceFromString(String xml) {
         return new TelephonyLookup(ReaderSupplier.forString(xml));
     }
 
@@ -182,23 +196,40 @@
              *     <network mcc="123" mnc="456" country="ab"/>
              *     <network mcc="123" mnc="567" country="cd"/>
              *   </networks>
+             *   <mobile_countries>
+             *     <mobile_country mcc="310"/>
+             *       <country>us</country>
+             *     </mobile_country>
+             *     <mobile_country mcc="340" default="gp">
+             *       <country>gp</country>
+             *       <country>gf</country>
+             *     </mobile_country>
+             *   </mobile_countries>
              * </telephony_lookup>
              */
 
             findNextStartTagOrThrowNoRecurse(parser, TELEPHONY_LOOKUP_ELEMENT);
 
-            // There is only one expected sub-element <telephony_lookup> in the format currently,
-            // skip over anything before it.
+            /* Start parsing <networks> */
             findNextStartTagOrThrowNoRecurse(parser, NETWORKS_ELEMENT);
-
             processNetworks(parser, processor);
-
-            // Make sure we are on the </networks> tag.
             checkOnEndTag(parser, NETWORKS_ELEMENT);
+            /* End parsing </networks> */
 
             // Advance to the next event.
             parser.next();
 
+            if (Flags.telephonyLookupMccExtension()) {
+                /* Start parsing <mobile_countries> */
+                findNextStartTagOrThrowNoRecurse(parser, MOBILE_COUNTRIES_ELEMENT);
+                processMobileCountries(parser, processor);
+                checkOnEndTag(parser, MOBILE_COUNTRIES_ELEMENT);
+                /* End parsing </mobile_countries> */
+
+                // Advance to the next event.
+                parser.next();
+            }
+
             // Skip anything until </telephony_lookup>, and make sure the file is not truncated and
             // we can find the end.
             consumeUntilEndTag(parser, TELEPHONY_LOOKUP_ELEMENT);
@@ -210,7 +241,6 @@
 
     private static void processNetworks(XmlPullParser parser,
             TelephonyNetworkProcessor processor) throws IOException, XmlPullParserException {
-
         // Skip over any unexpected elements and process <network> elements.
         while (findNextStartTagOrEndTagNoRecurse(parser, NETWORK_ELEMENT)) {
             String mcc = parser.getAttributeValue(
@@ -244,19 +274,44 @@
         }
     }
 
-    /**
-     * Processes &lt;network&gt; data.
-     */
-    private interface TelephonyNetworkProcessor {
+    private static void processMobileCountries(XmlPullParser parser,
+            TelephonyNetworkProcessor processor) throws IOException, XmlPullParserException {
+        // Skip over any unexpected elements and process <mobile_country> elements.
+        while (findNextStartTagOrEndTagNoRecurse(parser, MOBILE_COUNTRY_ELEMENT)) {
+            String mcc = parser.getAttributeValue(
+                    null /* namespace */, MOBILE_COUNTRY_CODE_ATTRIBUTE);
+            String defaultCountryIsoCode = parser.getAttributeValue(
+                    null /* namespace */, DEFAULT_ATTRIBUTE);
+            Set<String> countryIsoCodes = new HashSet<>();
 
-        boolean CONTINUE = true;
-        boolean HALT = false;
+            if (mcc == null) {
+                throw new XmlPullParserException(
+                        "Unable to find mcc: " + parser.getPositionDescription());
+            }
 
-        /**
-         * Process network data. Problems with the data are reported as an exception.
-         */
-        void processNetwork(String mcc, String mnc, String countryIso, String debugInfo)
-                throws XmlPullParserException;
+            while (findNextStartTagOrEndTagNoRecurse(parser, COUNTRY_ISO_CODE_ATTRIBUTE)) {
+                String countryIsoCode = consumeText(parser);
+                if (countryIsoCode == null) {
+                    throw new XmlPullParserException(
+                            "Unable to find country for mcc=" + mcc + ": "
+                                    + parser.getPositionDescription());
+                }
+                if (defaultCountryIsoCode == null) {
+                    defaultCountryIsoCode = countryIsoCode;
+                }
+                countryIsoCodes.add(countryIsoCode);
+
+                // Skip anything until </country>.
+                consumeUntilEndTag(parser, COUNTRY_ISO_CODE_ATTRIBUTE);
+            }
+
+            String debugInfo = parser.getPositionDescription();
+            processor.processMobileCountries(mcc, countryIsoCodes, defaultCountryIsoCode,
+                    debugInfo);
+
+            // Skip anything until </mobile_country>.
+            consumeUntilEndTag(parser, MOBILE_COUNTRY_ELEMENT);
+        }
     }
 
     /**
@@ -267,6 +322,7 @@
     private static class TelephonyNetworkValidator implements TelephonyNetworkProcessor {
 
         private final Set<MccMnc> knownMccMncs = new HashSet<>();
+        private final Set<String> knownMccs = new HashSet<>();
 
         @Override
         public void processNetwork(String mcc, String mnc, String countryIso, String debugInfo)
@@ -294,6 +350,43 @@
             knownMccMncs.add(mccMnc);
         }
 
+        @Override
+        public void processMobileCountries(String mcc, Set<String> countryIsoCodes,
+                String defaultCountryIso, String debugInfo) throws XmlPullParserException {
+            if (mcc == null || mcc.length() != 3 || !isAsciiNumeric(mcc)) {
+                throw new XmlPullParserException(
+                        "MCC is not valid: mcc=" + mcc + " at " + debugInfo);
+            }
+
+            if (countryIsoCodes.isEmpty()) {
+                throw new XmlPullParserException(
+                        "No country found for mcc=" + mcc + " at " + debugInfo);
+            }
+
+            if (!normalizeCountryIso(defaultCountryIso).equals(defaultCountryIso)) {
+                throw new XmlPullParserException("Default country code: " + defaultCountryIso
+                        + " is not normalized at " + debugInfo);
+            }
+
+            for (String countryIso : countryIsoCodes) {
+                if (!normalizeCountryIso(countryIso).equals(countryIso)) {
+                    throw new XmlPullParserException("Country code: " + countryIso
+                            + " is not normalized at " + debugInfo);
+                }
+            }
+
+            if (!countryIsoCodes.contains(defaultCountryIso)) {
+                throw new XmlPullParserException(
+                        "Default country not in country list for mcc=" + mcc + " at " + debugInfo);
+            }
+
+            if (knownMccs.contains(mcc)) {
+                throw new XmlPullParserException("Second entry for MCC: " + mcc
+                        + " at " + debugInfo);
+            }
+            knownMccs.add(mcc);
+        }
+
         private static boolean isAsciiNumeric(String string) {
             for (int i = 0; i < string.length(); i++) {
                 char character = string.charAt(i);
@@ -311,16 +404,40 @@
      */
     private static class TelephonyNetworksExtractor implements TelephonyNetworkProcessor {
         private List<TelephonyNetwork> networksList = new ArrayList<>(10 /* default */);
+        private List<MobileCountries> mobileCountries = new ArrayList<>();
 
         @Override
-        public void processNetwork(String mcc, String mnc, String countryIso, String debugInfo)
-                throws XmlPullParserException {
+        public void processNetwork(String mcc, String mnc, String countryIso, String debugInfo) {
             TelephonyNetwork network = TelephonyNetwork.create(mcc, mnc, countryIso);
             networksList.add(network);
         }
 
-        TelephonyNetworkFinder getTelephonyNetworkFinder() {
-            return TelephonyNetworkFinder.create(networksList);
+        @Override
+        public void processMobileCountries(String mcc, Set<String> countryIsos,
+                String defaultCountryIso, String debugInfo) {
+            mobileCountries.add(MobileCountries.create(mcc, countryIsos, defaultCountryIso));
         }
+
+        TelephonyNetworkFinder getTelephonyNetworkFinder() {
+            return TelephonyNetworkFinder.create(networksList, mobileCountries);
+        }
+    }
+
+    /**
+     * Processes &lt;network&gt; data.
+     */
+    private interface TelephonyNetworkProcessor {
+
+        boolean CONTINUE = true;
+        boolean HALT = false;
+
+        /**
+         * Process network data. Problems with the data are reported as an exception.
+         */
+        void processNetwork(String mcc, String mnc, String countryIso, String debugInfo)
+                throws XmlPullParserException;
+
+        void processMobileCountries(String mcc, Set<String> countryIsos, String defaultCountryIso,
+                String debugInfo) throws XmlPullParserException;
     }
 }
diff --git a/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TelephonyNetworkFinder.java b/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TelephonyNetworkFinder.java
index c6e5a89..0003efa 100644
--- a/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TelephonyNetworkFinder.java
+++ b/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TelephonyNetworkFinder.java
@@ -18,8 +18,12 @@
 
 import static com.android.i18n.timezone.XmlUtils.normalizeCountryIso;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
 import com.android.i18n.timezone.TelephonyNetwork.MccMnc;
 import com.android.i18n.util.Log;
+import com.android.icu.Flags;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -40,13 +44,16 @@
 
     private final Map<MccMnc, TelephonyNetwork> networksMap;
     private final List<TelephonyNetwork> networksList;
+    private final Map<String, MobileCountries> countriesByMcc;
 
-    public static TelephonyNetworkFinder create(List<TelephonyNetwork> networksList) {
+    public static TelephonyNetworkFinder create(List<TelephonyNetwork> networksList,
+            List<MobileCountries> mobileCountriesList) {
         Set<String> validCountryIsoCodes = new HashSet<>();
         for (String validCountryIsoCode : Locale.getISOCountries()) {
             validCountryIsoCodes.add(normalizeCountryIso(validCountryIsoCode));
         }
 
+        /* Generate network map */
         Map<MccMnc, TelephonyNetwork> networksMap = new HashMap<>();
         for (TelephonyNetwork network : networksList) {
             if (!validCountryIsoCodes.contains(network.getCountryIsoCode())) {
@@ -61,15 +68,46 @@
                         + ". New entry=" + network + " replacing previous entry.");
             }
         }
+        /* ************************* */
+
+        /* Generate countries map */
+        Map<String, MobileCountries> countriesByMcc = new HashMap<>();
+        for (MobileCountries mobileCountries : mobileCountriesList) {
+            for (String countryIsoCode : mobileCountries.getCountryIsoCodes()) {
+                if (!validCountryIsoCodes.contains(countryIsoCode)) {
+                    Log.w("Unrecognized country code: " + countryIsoCode
+                            + " for telephony MCC=" + mobileCountries.getMcc());
+                }
+            }
+
+            if (!validCountryIsoCodes.contains(mobileCountries.getDefaultCountryIsoCode())) {
+                Log.w("Unrecognized default country code: "
+                        + mobileCountries.getDefaultCountryIsoCode()
+                        + " for telephony MCC=" + mobileCountries.getMcc());
+            }
+
+            if (countriesByMcc.containsKey(mobileCountries.getMcc())) {
+                Log.w("Duplicate MCC detected for " + mobileCountries.getMcc()
+                        + ". New entry=" + mobileCountries
+                        + " replacing previous entry.");
+            }
+
+            countriesByMcc.put(mobileCountries.getMcc(), mobileCountries);
+        }
+        /* ************************* */
+
         return new TelephonyNetworkFinder(
                 Collections.unmodifiableList(new ArrayList<>(networksList)),
-                networksMap);
+                networksMap,
+                countriesByMcc);
     }
 
     private TelephonyNetworkFinder(List<TelephonyNetwork> networksList,
-            Map<MccMnc, TelephonyNetwork> networksMap) {
+            Map<MccMnc, TelephonyNetwork> networksMap,
+            Map<String, MobileCountries> countriesByMcc) {
         this.networksList = networksList;
         this.networksMap = networksMap;
+        this.countriesByMcc = countriesByMcc;
     }
 
     /**
@@ -82,8 +120,24 @@
         return networksMap.get(new MccMnc(mcc, mnc));
     }
 
+    /**
+     * Returns the countries where a given MCC is in use. It is expected for this method to return
+     * {@code null} if the MCC is not found.
+     */
+    @libcore.api.CorePlatformApi
+    @android.annotation.FlaggedApi(Flags.FLAG_TELEPHONY_LOOKUP_MCC_EXTENSION)
+    @Nullable
+    public MobileCountries findCountriesByMcc(@NonNull String mcc) {
+        return countriesByMcc.get(mcc);
+    }
+
     // @VisibleForTesting
-    public List<TelephonyNetwork> getAll() {
+    public List<TelephonyNetwork> getAllNetworks() {
         return networksList;
     }
+
+    // @VisibleForTesting
+    public List<MobileCountries> getAllMobileCountries() {
+        return countriesByMcc.values().stream().toList();
+    }
 }
diff --git a/android_icu4j/testing/src/com/android/i18n/test/timezone/MobileCountriesTest.java b/android_icu4j/testing/src/com/android/i18n/test/timezone/MobileCountriesTest.java
new file mode 100644
index 0000000..795194e
--- /dev/null
+++ b/android_icu4j/testing/src/com/android/i18n/test/timezone/MobileCountriesTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.i18n.test.timezone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import android.icu.testsharding.MainTestShard;
+import android.platform.test.annotations.UsesFlags;
+
+import com.android.i18n.timezone.MobileCountries;
+
+import org.junit.Test;
+
+import java.util.Set;
+
+@MainTestShard
+@UsesFlags(com.android.icu.Flags.class)
+public class MobileCountriesTest {
+
+    @Test
+    public void createMobileCountries_multipleRegions_expectNormalised() {
+        MobileCountries mobileCountries = MobileCountries.create("340", Set.of("GP", "GF"), "gp");
+
+        assertEquals("340", mobileCountries.getMcc());
+        assertEquals(Set.of("gp", "gf"), mobileCountries.getCountryIsoCodes());
+        assertEquals("gp", mobileCountries.getDefaultCountryIsoCode());
+    }
+
+    @Test
+    public void createMobileCountries_singleRegions_expectNormalised() {
+        MobileCountries mobileCountries = MobileCountries.create("222", Set.of("gr"), "GR");
+
+        assertEquals("222", mobileCountries.getMcc());
+        assertEquals(Set.of("gr"), mobileCountries.getCountryIsoCodes());
+        assertEquals("gr", mobileCountries.getDefaultCountryIsoCode());
+    }
+
+    @Test
+    public void createMobileCountries_defaultCountryNotInSet_shouldThrow() {
+        assertThrows(IllegalArgumentException.class,
+                () -> MobileCountries.create("340", Set.of("gr"), "gp"));
+    }
+
+    @Test
+    public void nullArguments_shouldThrow() {
+        assertThrows(NullPointerException.class,
+                () -> MobileCountries.create(null, Set.of("gr"), "GR"));
+        assertThrows(NullPointerException.class,
+                () -> MobileCountries.create("222", null, "GR"));
+        assertThrows(NullPointerException.class,
+                () -> MobileCountries.create("222", Set.of("gr"), null));
+    }
+}
\ No newline at end of file
diff --git a/android_icu4j/testing/src/com/android/i18n/test/timezone/TelephonyLookupTest.java b/android_icu4j/testing/src/com/android/i18n/test/timezone/TelephonyLookupTest.java
index 08d5db9..abf299a 100644
--- a/android_icu4j/testing/src/com/android/i18n/test/timezone/TelephonyLookupTest.java
+++ b/android_icu4j/testing/src/com/android/i18n/test/timezone/TelephonyLookupTest.java
@@ -18,18 +18,29 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
+import android.icu.testsharding.MainTestShard;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.annotations.UsesFlags;
+import android.platform.test.flag.junit.FlagsParameterization;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import com.android.i18n.timezone.MobileCountries;
 import com.android.i18n.timezone.TelephonyLookup;
 import com.android.i18n.timezone.TelephonyNetwork;
 import com.android.i18n.timezone.TelephonyNetworkFinder;
+import com.android.icu.Flags;
+import com.android.internal.telephony.MccTable;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
 import org.junit.Test;
-
-import android.icu.testsharding.MainTestShard;
+import org.junit.runner.RunWith;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
@@ -41,12 +52,33 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
+@RunWith(ParameterizedAndroidJunit4.class)
 @MainTestShard
+@UsesFlags(com.android.icu.Flags.class)
 public class TelephonyLookupTest {
+    @ClassRule
+    public static final SetFlagsRule.ClassRule mSetFlagsClassRule = new SetFlagsRule.ClassRule();
+
+    @Parameters(name = "{0}")
+    public static List<FlagsParameterization> getParams() {
+        return FlagsParameterization.allCombinationsOf(
+                Flags.FLAG_TELEPHONY_LOOKUP_MCC_EXTENSION);
+    }
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule;
 
     private Path testDir;
 
+    public TelephonyLookupTest(FlagsParameterization flags) {
+        mSetFlagsRule = mSetFlagsClassRule.createSetFlagsRule(flags);
+    }
+
     @Before
     public void setUp() throws Exception {
         testDir = Files.createTempDirectory("TelephonyLookupTest");
@@ -55,7 +87,7 @@
     @After
     public void tearDown() throws Exception {
         // Delete the testDir and all contents.
-        Files.walkFileTree(testDir, new SimpleFileVisitor<Path>() {
+        Files.walkFileTree(testDir, new SimpleFileVisitor<>() {
             @Override
             public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                     throws IOException {
@@ -74,21 +106,40 @@
 
     @Test
     public void createInstanceWithFallback() throws Exception {
-        String validXml1 = "<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n"
-                + "  </networks>\n"
-                + "</telephony_lookup>\n";
+        String validXml1 = """
+                <telephony_lookup>
+                  <networks>
+                    <network mcc="123" mnc="456" country="gb"/>
+                  </networks>
+                  <mobile_countries>
+                    <mobile_country mcc="202">
+                      <country>gr</country>
+                    </mobile_country>
+                  </mobile_countries>
+                </telephony_lookup>
+                """;
         TelephonyNetwork expectedTelephonyNetwork1 =
                 TelephonyNetwork.create("123", "456", "gb");
+        MobileCountries expectedMobileCountries1 =
+                MobileCountries.create("202", Set.of("gr"), "gr");
 
-        String validXml2 = "<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <network mcc=\"234\" mnc=\"567\" country=\"fr\"/>\n"
-                + "  </networks>\n"
-                + "</telephony_lookup>\n";
+        String validXml2 = """
+                <telephony_lookup>
+                  <networks>
+                    <network mcc="234" mnc="567" country="fr"/>
+                  </networks>
+                  <mobile_countries>
+                    <mobile_country mcc="505" default="au">
+                      <country>au</country>
+                      <country>nf</country>
+                    </mobile_country>
+                  </mobile_countries>
+                </telephony_lookup>
+                """;
         TelephonyNetwork expectedTelephonyNetwork2 =
                 TelephonyNetwork.create("234", "567", "fr");
+        MobileCountries expectedMobileCountries2 =
+                MobileCountries.create("505", Set.of("au", "nf"), "au");
 
         String invalidXml = "<foo></foo>\n";
         checkValidateThrowsParserException(invalidXml);
@@ -101,17 +152,38 @@
         TelephonyLookup file1ThenFile2 =
                 TelephonyLookup.createInstanceWithFallback(validFile1, validFile2);
         assertEquals(list(expectedTelephonyNetwork1),
-                file1ThenFile2.getTelephonyNetworkFinder().getAll());
+                file1ThenFile2.getTelephonyNetworkFinder().getAllNetworks());
+
+        if (Flags.telephonyLookupMccExtension()) {
+            assertEquals(list(expectedMobileCountries1),
+                    file1ThenFile2.getTelephonyNetworkFinder().getAllMobileCountries());
+        } else {
+            assertEmpty(file1ThenFile2.getTelephonyNetworkFinder().getAllMobileCountries());
+        }
 
         TelephonyLookup missingFileThenFile1 =
                 TelephonyLookup.createInstanceWithFallback(missingFile, validFile1);
         assertEquals(list(expectedTelephonyNetwork1),
-                missingFileThenFile1.getTelephonyNetworkFinder().getAll());
+                missingFileThenFile1.getTelephonyNetworkFinder().getAllNetworks());
+
+        if (Flags.telephonyLookupMccExtension()) {
+            assertEquals(list(expectedMobileCountries1),
+                    missingFileThenFile1.getTelephonyNetworkFinder().getAllMobileCountries());
+        } else {
+            assertEmpty(missingFileThenFile1.getTelephonyNetworkFinder().getAllMobileCountries());
+        }
 
         TelephonyLookup file2ThenFile1 =
                 TelephonyLookup.createInstanceWithFallback(validFile2, validFile1);
         assertEquals(list(expectedTelephonyNetwork2),
-                file2ThenFile1.getTelephonyNetworkFinder().getAll());
+                file2ThenFile1.getTelephonyNetworkFinder().getAllNetworks());
+
+        if (Flags.telephonyLookupMccExtension()) {
+            assertEquals(list(expectedMobileCountries2),
+                    file2ThenFile1.getTelephonyNetworkFinder().getAllMobileCountries());
+        } else {
+            assertEmpty(file2ThenFile1.getTelephonyNetworkFinder().getAllMobileCountries());
+        }
 
         // We assume the file has been validated so an invalid file is not checked ahead of time.
         // We will find out when we look something up.
@@ -122,44 +194,110 @@
         // This is not a normal case: It would imply a device shipped without a file anywhere!
         TelephonyLookup missingFiles =
                 TelephonyLookup.createInstanceWithFallback(missingFile, missingFile);
-        assertEmpty(missingFiles.getTelephonyNetworkFinder().getAll());
+        assertEmpty(missingFiles.getTelephonyNetworkFinder().getAllNetworks());
+        assertEmpty(missingFiles.getTelephonyNetworkFinder().getAllMobileCountries());
     }
 
     @Test
-    public void xmlParsing_emptyFile() throws Exception {
+    public void xmlParsing_emptyFile() {
         checkValidateThrowsParserException("");
     }
 
     @Test
-    public void xmlParsing_unexpectedRootElement() throws Exception {
+    public void xmlParsing_unexpectedRootElement() {
         checkValidateThrowsParserException("<foo></foo>\n");
     }
 
     @Test
-    public void xmlParsing_missingNetworks() throws Exception {
-        checkValidateThrowsParserException("<telephony_lookup></telephony_lookup>\n");
+    public void xmlParsing_missingNetworks() {
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                  <mobile_countries>
+                    <mobile_country mcc="505" default="au">
+                      <country>au</country>
+                      <country>nf</country>
+                    </mobile_country>
+                  </mobile_countries>
+                </telephony_lookup>
+                """);
     }
 
     @Test
-    public void xmlParsing_emptyNetworksOk() throws Exception {
+    public void xmlParsing_missingMobileCountries() {
+        assumeTrue(Flags.telephonyLookupMccExtension());
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                  <networks>
+                    <network mcc="234" mnc="567" country="fr"/>
+                  </networks>
+                </telephony_lookup>
+                """);
+    }
+
+    @Test
+    public void xmlParsing_emptyNetworkOk() throws Exception {
         {
             TelephonyLookup telephonyLookup =
-                    validate("<telephony_lookup>\n"
-                            + "  <networks>\n"
-                            + "  </networks>\n"
-                            + "</telephony_lookup>\n");
+                    validate("""
+                            <telephony_lookup>
+                              <networks></networks>
+                              <mobile_countries>
+                                <mobile_country mcc="505" default="au">
+                                  <country>au</country>
+                                </mobile_country>
+                              </mobile_countries>
+                            </telephony_lookup>
+                            """);
             TelephonyNetworkFinder telephonyNetworkFinder = telephonyLookup
                     .getTelephonyNetworkFinder();
-            assertEquals(list(), telephonyNetworkFinder.getAll());
+            assertEquals(list(), telephonyNetworkFinder.getAllNetworks());
         }
         {
             TelephonyLookup telephonyLookup =
-                    validate("<telephony_lookup>\n"
-                            + "  <networks/>\n"
-                            + "</telephony_lookup>\n");
+                    validate("""
+                            <telephony_lookup>
+                              <networks/>
+                              <mobile_countries>
+                                <mobile_country mcc="505" default="au">
+                                  <country>au</country>
+                                </mobile_country>
+                              </mobile_countries>
+                            </telephony_lookup>
+                            """);
             TelephonyNetworkFinder telephonyNetworkFinder = telephonyLookup
                     .getTelephonyNetworkFinder();
-            assertEquals(list(), telephonyNetworkFinder.getAll());
+            assertEquals(list(), telephonyNetworkFinder.getAllNetworks());
+        }
+    }
+
+    @Test
+    public void xmlParsing_emptyMobileCountries() throws Exception {
+        assumeTrue(Flags.telephonyLookupMccExtension());
+
+        {
+            TelephonyLookup telephonyLookup =
+                    validate("""
+                            <telephony_lookup>
+                             <networks/>
+                             <mobile_countries>
+                             </mobile_countries>
+                            </telephony_lookup>
+                            """);
+            TelephonyNetworkFinder telephonyNetworkFinder = telephonyLookup
+                    .getTelephonyNetworkFinder();
+            assertEmpty(telephonyNetworkFinder.getAllMobileCountries());
+        }
+        {
+            TelephonyLookup telephonyLookup =
+                    validate("""
+                             <telephony_lookup>
+                              <networks/>
+                              <mobile_countries/>
+                             </telephony_lookup>
+                             """);
+            TelephonyNetworkFinder telephonyNetworkFinder = telephonyLookup
+                    .getTelephonyNetworkFinder();
+            assertEmpty(telephonyNetworkFinder.getAllMobileCountries());
         }
     }
 
@@ -167,14 +305,33 @@
     public void xmlParsing_unexpectedComments() throws Exception {
         TelephonyNetwork expectedTelephonyNetwork =
                 TelephonyNetwork.create("123", "456", "gb");
+        MobileCountries expectedMobileCountries =
+                MobileCountries.create("202", Set.of("gr"), "gr");
 
-        TelephonyLookup telephonyLookup = validate("<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <!-- This is a comment -->"
-                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n"
-                + "  </networks>\n"
-                + "</telephony_lookup>\n");
-        assertEquals(list(expectedTelephonyNetwork), telephonyLookup.getTelephonyNetworkFinder().getAll());
+        TelephonyLookup telephonyLookup = validate("""
+                <telephony_lookup>
+                  <networks>
+                    <!-- This is a comment -->
+                    <network mcc="123" mnc="456" country="gb"/>
+                  </networks>
+                  <!-- This is a comment -->
+                  <mobile_countries>
+                    <!-- This is a comment -->
+                    <mobile_country mcc="202">
+                      <!-- This is a comment -->
+                      <country>gr</country>
+                    </mobile_country>
+                  </mobile_countries>
+                  <!-- This is a comment -->
+                </telephony_lookup>
+                """);
+        assertEquals(list(expectedTelephonyNetwork),
+                telephonyLookup.getTelephonyNetworkFinder().getAllNetworks());
+
+        if (Flags.telephonyLookupMccExtension()) {
+            assertEquals(list(expectedMobileCountries),
+                    telephonyLookup.getTelephonyNetworkFinder().getAllMobileCountries());
+        }
     }
 
     @Test
@@ -182,6 +339,9 @@
         TelephonyNetwork expectedTelephonyNetwork =
                 TelephonyNetwork.create("123", "456", "gb");
         List<TelephonyNetwork> expectedNetworks = list(expectedTelephonyNetwork);
+        MobileCountries expectedMobileCountries =
+                MobileCountries.create("202", Set.of("gr"), "gr");
+        List<MobileCountries> expectedMobileCountriesList = list(expectedMobileCountries);
 
         String unexpectedElement = "<unexpected-element>\n<a /></unexpected-element>\n";
 
@@ -195,28 +355,52 @@
                 + "    " + unexpectedElement
                 + "  </networks>\n"
                 + "  " + unexpectedElement
-                + "</telephony_lookup>\n");
-        assertEquals(expectedNetworks, telephonyLookup.getTelephonyNetworkFinder().getAll());
-
-        telephonyLookup = validate("<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\">\n"
+                + "  <mobile_countries>\n"
+                + "   " + unexpectedElement
+                + "    <mobile_country mcc=\"202\">\n"
                 + "    " + unexpectedElement
-                + "    </network>\n"
-                + "  </networks>\n"
+                + "     <country>gr</country>\n"
+                + "    " + unexpectedElement
+                + "    </mobile_country>\n"
+                + "   " + unexpectedElement
+                + "  </mobile_countries>\n"
+                + " " + unexpectedElement
                 + "</telephony_lookup>\n");
-        assertEquals(expectedNetworks, telephonyLookup.getTelephonyNetworkFinder().getAll());
+        assertEquals(expectedNetworks,
+                telephonyLookup.getTelephonyNetworkFinder().getAllNetworks());
+
+        if (Flags.telephonyLookupMccExtension()) {
+            assertEquals(expectedMobileCountriesList,
+                    telephonyLookup.getTelephonyNetworkFinder().getAllMobileCountries());
+        }
 
         expectedNetworks = list(expectedTelephonyNetwork,
                 TelephonyNetwork.create("234", "567", "fr"));
+        expectedMobileCountriesList = list(expectedMobileCountries,
+                MobileCountries.create("204", Set.of("nl"), "nl"));
         telephonyLookup = validate("<telephony_lookup>\n"
                 + "  <networks>\n"
                 + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n"
                 + "    " + unexpectedElement
                 + "    <network mcc=\"234\" mnc=\"567\" country=\"fr\"/>\n"
                 + "  </networks>\n"
+                + "  <mobile_countries>\n"
+                + "    <mobile_country mcc=\"202\">\n"
+                + "     <country>gr</country>\n"
+                + "    </mobile_country>\n"
+                + "   " + unexpectedElement
+                + "    <mobile_country mcc=\"204\">\n"
+                + "     <country>nl</country>\n"
+                + "    </mobile_country>\n"
+                + "  </mobile_countries>\n"
                 + "</telephony_lookup>\n");
-        assertEquals(expectedNetworks, telephonyLookup.getTelephonyNetworkFinder().getAll());
+        assertEquals(expectedNetworks,
+                telephonyLookup.getTelephonyNetworkFinder().getAllNetworks());
+
+        if (Flags.telephonyLookupMccExtension()) {
+            assertEquals(expectedMobileCountriesList,
+                    telephonyLookup.getTelephonyNetworkFinder().getAllMobileCountries());
+        }
     }
 
     @Test
@@ -224,6 +408,9 @@
         TelephonyNetwork expectedTelephonyNetwork =
                 TelephonyNetwork.create("123", "456", "gb");
         List<TelephonyNetwork> expectedNetworks = list(expectedTelephonyNetwork);
+        MobileCountries expectedMobileCountries =
+                MobileCountries.create("202", Set.of("gr"), "gr");
+        List<MobileCountries> expectedMobileCountriesList = list(expectedMobileCountries);
 
         String unexpectedText = "unexpected-text";
         TelephonyLookup telephonyLookup = validate("<telephony_lookup>\n"
@@ -234,116 +421,314 @@
                 + "    " + unexpectedText
                 + "  </networks>\n"
                 + "  " + unexpectedText
+                + "  <mobile_countries>\n"
+                + "  " + unexpectedText
+                + "    <mobile_country mcc=\"202\">\n"
+                + "   " + unexpectedText
+                + "     <country>gr</country>\n"
+                + "   " + unexpectedText
+                + "    </mobile_country>\n"
+                + "  " + unexpectedText
+                + "  </mobile_countries>\n"
+                + " " + unexpectedText
                 + "</telephony_lookup>\n");
-        assertEquals(expectedNetworks, telephonyLookup.getTelephonyNetworkFinder().getAll());
+        assertEquals(expectedNetworks,
+                telephonyLookup.getTelephonyNetworkFinder().getAllNetworks());
 
-        telephonyLookup = validate("<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\">\n"
-                + "      " + unexpectedText
-                + "    </network>\n"
-                + "  </networks>\n"
-                + "</telephony_lookup>\n");
-        assertEquals(expectedNetworks, telephonyLookup.getTelephonyNetworkFinder().getAll());
+        if (Flags.telephonyLookupMccExtension()) {
+            assertEquals(expectedMobileCountriesList,
+                    telephonyLookup.getTelephonyNetworkFinder().getAllMobileCountries());
+        } else {
+            assertEmpty(telephonyLookup.getTelephonyNetworkFinder().getAllMobileCountries());
+        }
     }
 
     @Test
-    public void xmlParsing_truncatedInput() throws Exception {
+    public void xmlParsing_truncatedInput() {
         checkValidateThrowsParserException("<telephony_lookup>\n");
 
-        checkValidateThrowsParserException("<telephony_lookup>\n"
-                + "  <networks>\n");
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                  <networks>
+                """);
 
-        checkValidateThrowsParserException("<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n");
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                  <networks>
+                    <network mcc="123" mnc="456" country="gb"/>
+                """);
 
-        checkValidateThrowsParserException("<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n"
-                + "  </networks>\n");
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                  <networks>
+                    <network mcc="123" mnc="456" country="gb"/>
+                  </networks>
+                """);
+
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                  <networks>
+                    <network mcc="123" mnc="456" country="gb"/>
+                  </networks>
+                  <mobile_countries>
+                """);
+
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                  <networks>
+                    <network mcc="123" mnc="456" country="gb"/>
+                  </networks>
+                  <mobile_countries>
+                    <mobile_country mcc="202">
+                """);
+
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                  <networks>
+                    <network mcc="123" mnc="456" country="gb"/>
+                  </networks>
+                  <mobile_countries>
+                    <mobile_country mcc="202">
+                      <country>gr</country>
+                """);
+
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                  <networks>
+                    <network mcc="123" mnc="456" country="gb"/>
+                  </networks>
+                  <mobile_countries>
+                    <mobile_country mcc="202">
+                      <country>gr</country>
+                    </mobile_country>
+                  </mobile_countries>
+                """);
     }
 
     @Test
     public void validateDuplicateMccMnc() {
-        checkValidateThrowsParserException("<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <network mcc=\"123\" mnc=\"456\" countryCode=\"gb\"/>\n"
-                + "    <network mcc=\"123\" mnc=\"456\" countryCode=\"fr\"/>\n"
-                + "  </networks>\n"
-                + "</telephony_lookup>\n");
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                  <networks>
+                    <network mcc="123" mnc="456" countryCode="gb"/>
+                    <network mcc="123" mnc="456" countryCode="fr"/>
+                  </networks>
+                  <mobile_countries>
+                    <mobile_country mcc="202">
+                      <country>gr</country>
+                    </mobile_country>
+                  </mobile_countries>
+                </telephony_lookup>
+                """);
+    }
+
+    @Test
+    public void validateDuplicateMcc() {
+        assumeTrue(Flags.telephonyLookupMccExtension());
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                  <networks>
+                    <network mcc="123" mnc="456" countryCode="gb"/>
+                  </networks>
+                  <mobile_countries>
+                    <mobile_country mcc="202">
+                      <country>gr</country>
+                    </mobile_country>
+                    <mobile_country mcc="202">
+                      <country>nl</country>
+                    </mobile_country>
+                  </mobile_countries>
+                </telephony_lookup>
+                """);
     }
 
     @Test
     public void validateCountryCodeLowerCase() {
-        checkValidateThrowsParserException("<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <network mcc=\"123\" mnc=\"456\" countryCode=\"GB\"/>\n"
-                + "  </networks>\n"
-                + "</telephony_lookup>\n");
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                 <networks>
+                 <network mcc="123" mnc="456" countryCode="GB"/>
+                 </networks>
+                 <mobile_countries>
+                  <mobile_country mcc="202">
+                   <country>gr</country>
+                  </mobile_country>
+                 </mobile_countries>
+                </telephony_lookup>
+                """);
+
+        if (Flags.telephonyLookupMccExtension()) {
+            checkValidateThrowsParserException("""
+                    <telephony_lookup>
+                      <networks>
+                       <network mcc="123" mnc="456" countryCode="gb"/>
+                      </networks>
+                      <mobile_countries>
+                       <mobile_country mcc="202">
+                        <country>GR</country>
+                       </mobile_country>
+                      </mobile_countries>
+                    </telephony_lookup>
+                    """);
+        }
     }
 
-
     @Test
-    public void getTelephonyNetworkFinder() throws Exception {
-        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceForTests(
-                "<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n"
-                + "    <network mcc=\"234\" mnc=\"567\" country=\"fr\"/>\n"
-                + "  </networks>\n"
-                + "</telephony_lookup>\n");
+    public void getTelephonyNetworkFinder() {
+        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceFromString("""
+                <telephony_lookup>
+                  <networks>
+                   <network mcc="123" mnc="456" country="gb"/>
+                   <network mcc="234" mnc="567" country="fr"/>
+                  </networks>
+                  <mobile_countries>
+                   <mobile_country mcc="202">
+                     <country>gr</country>
+                   </mobile_country>
+                   <mobile_country mcc="505" default="au">
+                     <country>au</country>
+                     <country>nf</country>
+                   </mobile_country>
+                  </mobile_countries>
+                </telephony_lookup>
+                """);
 
         TelephonyNetworkFinder telephonyNetworkFinder = telephonyLookup.getTelephonyNetworkFinder();
         TelephonyNetwork expectedNetwork1 = TelephonyNetwork.create("123", "456", "gb");
         TelephonyNetwork expectedNetwork2 = TelephonyNetwork.create("234", "567", "fr");
-        assertEquals(list(expectedNetwork1, expectedNetwork2), telephonyNetworkFinder.getAll());
+        MobileCountries expectedMobileCountries1 =
+                MobileCountries.create("202", Set.of("gr"), "gr");
+        MobileCountries expectedMobileCountries2 =
+                MobileCountries.create("505", Set.of("au", "nf"), "au");
+
+        assertEquals(list(expectedNetwork1, expectedNetwork2),
+                telephonyNetworkFinder.getAllNetworks());
+
+        if (Flags.telephonyLookupMccExtension()) {
+            assertEquals(list(expectedMobileCountries1, expectedMobileCountries2),
+                    telephonyNetworkFinder.getAllMobileCountries());
+        } else {
+            assertEmpty(telephonyNetworkFinder.getAllMobileCountries());
+        }
+
         assertEquals(expectedNetwork1, telephonyNetworkFinder.findNetworkByMccMnc("123", "456"));
         assertEquals(expectedNetwork2, telephonyNetworkFinder.findNetworkByMccMnc("234", "567"));
         assertNull(telephonyNetworkFinder.findNetworkByMccMnc("999", "999"));
-    }
 
-    @Test
-    public void xmlParsing_missingMccAttribute() throws Exception {
-        checkValidateThrowsParserException("<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <network mnc=\"456\" country=\"gb\"/>\n"
-                + "  </networks>\n"
-                + "</telephony_lookup>\n");
-    }
-
-    @Test
-    public void xmlParsing_missingMncAttribute() throws Exception {
-        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceForTests(
-                "<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <network mcc=\"123\" country=\"gb\"/>\n"
-                + "  </networks>\n"
-                + "</telephony_lookup>\n");
-        assertNull(telephonyLookup.getTelephonyNetworkFinder());
-    }
-
-    @Test
-    public void xmlParsing_missingCountryCodeAttribute() throws Exception {
-        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceForTests(
-                "<telephony_lookup>\n"
-                + "  <networks>\n"
-                + "    <network mcc=\"123\" mnc=\"456\"/>\n"
-                + "  </networks>\n"
-                + "</telephony_lookup>\n");
-        assertNull(telephonyLookup.getTelephonyNetworkFinder());
-    }
-
-    private static void checkValidateThrowsParserException(String xml) {
-        try {
-            validate(xml);
-            fail();
-        } catch (IOException expected) {
+        if (Flags.telephonyLookupMccExtension()) {
+            assertEquals(expectedMobileCountries1,
+                    telephonyNetworkFinder.findCountriesByMcc("202"));
+            assertEquals(expectedMobileCountries2,
+                    telephonyNetworkFinder.findCountriesByMcc("505"));
+            assertNull(telephonyNetworkFinder.findCountriesByMcc("999"));
         }
     }
 
+    @Test
+    public void xmlParsing_networks_missingMccAttribute() {
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                 <networks>
+                  <network mnc="456" country="gb"/>
+                 </networks>
+                 <mobile_countries>
+                  <mobile_country mcc="202">
+                   <country>gr</country>
+                  </mobile_country>
+                 </mobile_countries>
+                </telephony_lookup>
+                """);
+    }
+
+    @Test
+    public void xmlParsing_mobileCountries_missingMccAttribute() {
+        assumeTrue(Flags.telephonyLookupMccExtension());
+        checkValidateThrowsParserException("""
+                <telephony_lookup>
+                 <networks>
+                  <network mcc="123" mnc="456" country="gb"/>
+                 </networks>
+                 <mobile_countries>
+                  <mobile_country>
+                   <country>gr</country>
+                  </mobile_country>
+                 </mobile_countries>
+                </telephony_lookup>
+                """);
+    }
+
+    @Test
+    public void xmlParsing_networks_missingMncAttribute() {
+        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceFromString("""
+                <telephony_lookup>
+                 <networks>
+                  <network mcc="123" country="gb"/>
+                 </networks>
+                 <mobile_countries>
+                  <mobile_country mcc="202">
+                   <country>gr</country>
+                  </mobile_country>
+                 </mobile_countries>
+                </telephony_lookup>
+                """);
+        assertNull(telephonyLookup.getTelephonyNetworkFinder());
+    }
+
+    @Test
+    public void xmlParsing_network_missingCountryCodeAttribute() {
+        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceFromString("""
+                <telephony_lookup>
+                 <networks>
+                  <network mcc="123" mnc="456"/>
+                 </networks>
+                 <mobile_countries>
+                  <mobile_country mcc="202">
+                   <country>gr</country>
+                  </mobile_country>
+                 </mobile_countries>
+                </telephony_lookup>
+                """);
+        assertNull(telephonyLookup.getTelephonyNetworkFinder());
+    }
+
+    @Test
+    public void xmlParsing_mobileCountry_missingCountryCode() {
+        assumeTrue(Flags.telephonyLookupMccExtension());
+        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceFromString("""
+                <telephony_lookup>
+                 <networks>
+                  <network mcc="123" mnc="456" country="gb"/>
+                 </networks>
+                 <mobile_countries>
+                  <mobile_country mcc="202">
+                   <country/>
+                  </mobile_country>
+                 </mobile_countries>
+                </telephony_lookup>
+                """);
+        assertNull(telephonyLookup.getTelephonyNetworkFinder());
+    }
+
+    @EnableFlags(Flags.FLAG_TELEPHONY_LOOKUP_MCC_EXTENSION)
+    @Test
+    public void telephonyFinder_shouldBeIdenticalToTelephonyMccTable() {
+        TelephonyNetworkFinder telephonyNetworkFinder =
+                TelephonyLookup.getInstance().getTelephonyNetworkFinder();
+
+        telephonyNetworkFinder.getAllMobileCountries().forEach(countries -> {
+            String telephonyCountry = MccTable.geoCountryCodeForMccMnc(
+                    new MccTable.MccMnc(countries.getMcc(), null));
+
+            assertEquals(telephonyCountry, countries.getDefaultCountryIsoCode());
+        });
+    }
+
+    private static void checkValidateThrowsParserException(String xml) {
+        assertThrows(IOException.class, () -> validate(xml));
+    }
+
     private static TelephonyLookup validate(String xml) throws IOException {
-        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceForTests(xml);
+        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceFromString(xml);
         telephonyLookup.validate();
         return telephonyLookup;
     }
diff --git a/android_icu4j/testing/src/com/android/i18n/test/timezone/TelephonyNetworkFinderTest.java b/android_icu4j/testing/src/com/android/i18n/test/timezone/TelephonyNetworkFinderTest.java
index 6b638cf..14b3b64 100644
--- a/android_icu4j/testing/src/com/android/i18n/test/timezone/TelephonyNetworkFinderTest.java
+++ b/android_icu4j/testing/src/com/android/i18n/test/timezone/TelephonyNetworkFinderTest.java
@@ -17,35 +17,91 @@
 package com.android.i18n.test.timezone;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-
-import com.android.i18n.timezone.TelephonyNetwork;
-import com.android.i18n.timezone.TelephonyNetworkFinder;
-
-import org.junit.Test;
+import static org.junit.Assert.assertThrows;
 
 import android.icu.testsharding.MainTestShard;
+import android.platform.test.annotations.UsesFlags;
+import android.platform.test.flag.junit.FlagsParameterization;
+import android.platform.test.flag.junit.SetFlagsRule;
 
-import java.util.Arrays;
+import com.android.i18n.timezone.MobileCountries;
+import com.android.i18n.timezone.TelephonyNetwork;
+import com.android.i18n.timezone.TelephonyNetworkFinder;
+import com.android.icu.Flags;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.List;
+import java.util.Set;
 
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
+@RunWith(ParameterizedAndroidJunit4.class)
 @MainTestShard
+@UsesFlags(com.android.icu.Flags.class)
 public class TelephonyNetworkFinderTest {
+    @ClassRule
+    public static final SetFlagsRule.ClassRule mSetFlagsClassRule = new SetFlagsRule.ClassRule();
+
+    @Parameters(name = "{0}")
+    public static List<FlagsParameterization> getParams() {
+        return FlagsParameterization.allCombinationsOf(
+                Flags.FLAG_TELEPHONY_LOOKUP_MCC_EXTENSION);
+    }
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule;
+
+    private TelephonyNetworkFinder finder;
+
+    public TelephonyNetworkFinderTest(FlagsParameterization flags) {
+        mSetFlagsRule = mSetFlagsClassRule.createSetFlagsRule(flags);
+    }
+
+    @Before
+    public void setup() {
+        List<TelephonyNetwork> networkList = List.of(
+                TelephonyNetwork.create("123", "456", "gb"),
+                TelephonyNetwork.create("234", "567", "gb"));
+
+        List<MobileCountries> mobileCountriesList = List.of(
+                MobileCountries.create("234", Set.of("uk"), "uk"),
+                MobileCountries.create("310", Set.of("uk", "us"), "us"));
+
+        finder = TelephonyNetworkFinder.create(networkList, mobileCountriesList);
+    }
 
     @Test
-    public void testCreateAndLookups() {
+    public void telephonyFinder_shouldFindNetworks() {
         TelephonyNetwork network = TelephonyNetwork.create("123", "456", "gb");
-        List<TelephonyNetwork> networkList = list(network);
-        TelephonyNetworkFinder finder = TelephonyNetworkFinder.create(networkList);
+
         assertEquals(network, finder.findNetworkByMccMnc("123", "456"));
         assertNull(finder.findNetworkByMccMnc("XXX", "XXX"));
         assertNull(finder.findNetworkByMccMnc("123", "XXX"));
         assertNull(finder.findNetworkByMccMnc("456", "123"));
         assertNull(finder.findNetworkByMccMnc("111", "222"));
-        assertEquals(networkList, finder.getAll());
+        assertEquals(2, finder.getAllNetworks().size());
     }
 
-    private static <X> List<X> list(X... values) {
-        return Arrays.asList(values);
+    @Test
+    public void telephonyFinder_shouldFindCountries() {
+        MobileCountries countries = MobileCountries.create("310", Set.of("uk", "us"), "us");
+
+        assertEquals(countries, finder.findCountriesByMcc("310"));
+        assertNotNull(finder.findCountriesByMcc("234"));
+        assertEquals(2, finder.getAllMobileCountries().size());
+    }
+
+    @Test
+    public void telephonyFinder_countryIsoCodes_cannotBeTamperedWith() {
+        MobileCountries found = finder.findCountriesByMcc("310");
+        assertThrows(UnsupportedOperationException.class, () -> found.getCountryIsoCodes().add("gb"));
     }
 }
diff --git a/icu.aconfig b/icu.aconfig
index 9f97578..27aa57b 100644
--- a/icu.aconfig
+++ b/icu.aconfig
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 package: "com.android.icu"
-container: "system"
+container: "com.android.i18n"
 
 flag {
     namespace: "core_libraries"
@@ -34,3 +34,13 @@
     # ICU is used before SettingsProvider starts
     is_fixed_read_only: true
 }
+
+flag {
+    namespace: "core_libraries"
+    name: "telephony_lookup_mcc_extension"
+    is_exported: true
+    description: "This flag controls whether to parse the new MCC to countries mapping from telephony lookup"
+    bug: "376493245"
+    # ICU is used before SettingsProvider starts
+    is_fixed_read_only: true
+}