Add support for defaultTimeZoneBoost

Add support for a mechanism to "boost" a country's default time zone at
runtime. See the comments in countryzones.txt for details.

Enable the boost for 4 countries. See the associated comments for
details.

Test: Ran the update-tzdata.py script and inspected the output
Bug: 141727033
Change-Id: I6afeb75e702b974e7e1b19a301c9e47b01d95db4
diff --git a/input_data/android/countryzones.txt b/input_data/android/countryzones.txt
index 530bbf2..a78447b 100644
--- a/input_data/android/countryzones.txt
+++ b/input_data/android/countryzones.txt
@@ -40,18 +40,39 @@
 # zones.tab file.
 #
 # defaultTimeZoneId:
-# The (optional) defaultTimeZoneId is used to specify which of the time
+# The optional defaultTimeZoneId is used to specify which of the time
 # zones associated with the country should be used if only
 # a country code is available. If it is not specified and the country
 # has only one obvious choice then the defaultTimeZoneId can be omitted.
 #
+# defaultTimeZoneBoost:
+# An optional boolean value that can be used to provide a boost to
+# decision-making around the defaultTimeZoneId at runtime based on factors that are not
+# obvious from the time zone data alone.
+#
+# For ease of maintenance, it is recommended that this value is only specified
+# where the default selection criteria wouldn't otherwise do the right thing
+# and where defaultTimeZoneId is explicitly specified.
+#
+# false: the defaultTimeZoneId is to be treated "normally". i.e.
+#     defaultTimeZoneId can be used in obvious cases (e.g. where the country
+#     only uses a single zone), or where _any_ time zone is considered better
+#     than nothing (e.g. for defaulting in UIs or setting zones on an
+#     uninitialized device).
+# true: the defaultTimeZoneId is to be treated as a "strong" signal. i.e. if
+#     supporting information isn't available, or it is and doesn't help pick
+#     a distinct zone, then the defaultTimeZoneId is a good choice for devices
+#     in the country. This is useful for countries like New Zealand which the
+#     data tells us has two zones, but in reality the overwhelming majority of
+#     the population uses a single zone.
+#
 # timeZoneMappings:
 # Time zones associated with the country and associated metadata.
 #
 # The ordering of TimeZoneMapping elements is important because it influence
-# the order that time zones in a country are considered when the device
-# has a known local time, offset from UTC and whether the local zone is
-# currently observing DST.
+# the order that time zones in a country are considered when the device is
+# trying to detect a time zone and has a known local time, offset from UTC,
+# and whether the local zone is currently observing DST.
 #
 # There will often be several time zones within a country that could match
 # at any given instant, but the first zone that matches a user's country,
@@ -232,6 +253,15 @@
 countries:<
   isoCode:"ar"
   defaultTimeZoneId:"America/Argentina/Buenos_Aires"
+
+  # Boost the strength of the country default:
+  # Argentina is known to have one zone so we explicitly boost the strength of
+  # the country default. The generated tzlookup.xml data says there are two
+  # zones because the generator uses CLDR data to determine if zone names are
+  # the same and there is a CLDR bug with America/Argentina/San_Luis; "Western
+  # Argentina Standard Time" is not a thing. http://b/77677947
+  defaultTimeZoneBoost: true
+
   timeZoneMappings:<
     utcOffset:"-3:00"
     id:"America/Argentina/Buenos_Aires"
@@ -1012,6 +1042,11 @@
 countries:<
   isoCode:"cn"
   defaultTimeZoneId:"Asia/Shanghai"
+
+  # Boost the strength of the country default:
+  # >99% of the population use "Asia/Shanghai"
+  defaultTimeZoneBoost: true
+
   timeZoneMappings:<
     utcOffset:"8:00"
     id:"Asia/Shanghai"
@@ -1169,6 +1204,11 @@
 countries:<
   isoCode:"ec"
   defaultTimeZoneId:"America/Guayaquil"
+
+  # Boost the strength of the country default:
+  # Pacific/Galapagos covers only ~25k people Vs ~16m total population.
+  defaultTimeZoneBoost: true
+
   timeZoneMappings:<
     utcOffset:"-5:00"
     id:"America/Guayaquil"
@@ -2350,6 +2390,11 @@
 countries:<
   isoCode:"nz"
   defaultTimeZoneId:"Pacific/Auckland"
+
+  # Boost the strength of the country default:
+  # Pacific/Chatham only covers ~600 people.
+  defaultTimeZoneBoost: true
+
   timeZoneMappings:<
     utcOffset:"12:00"
     id:"Pacific/Auckland"
diff --git a/output_data/android/tzlookup.xml b/output_data/android/tzlookup.xml
index d39d311..f514e79 100644
--- a/output_data/android/tzlookup.xml
+++ b/output_data/android/tzlookup.xml
@@ -40,7 +40,7 @@
    <id>Antarctica/Rothera</id>
    <id>Antarctica/Palmer</id>
   </country>
-  <country code="ar" default="America/Argentina/Buenos_Aires" everutc="n">
+  <country code="ar" default="America/Argentina/Buenos_Aires" defaultBoost="y" everutc="n">
    <id>America/Argentina/Buenos_Aires</id>
    <id notafter="687931200000">America/Argentina/Cordoba</id>
    <id notafter="1096171200000">America/Argentina/Salta</id>
@@ -219,7 +219,7 @@
   <country code="cm" default="Africa/Douala" everutc="n">
    <id>Africa/Douala</id>
   </country>
-  <country code="cn" default="Asia/Shanghai" everutc="n">
+  <country code="cn" default="Asia/Shanghai" defaultBoost="y" everutc="n">
    <id>Asia/Shanghai</id>
    <id>Asia/Urumqi</id>
   </country>
@@ -267,7 +267,7 @@
   <country code="dz" default="Africa/Algiers" everutc="n">
    <id>Africa/Algiers</id>
   </country>
-  <country code="ec" default="America/Guayaquil" everutc="n">
+  <country code="ec" default="America/Guayaquil" defaultBoost="y" everutc="n">
    <id>America/Guayaquil</id>
    <id>Pacific/Galapagos</id>
   </country>
@@ -621,7 +621,7 @@
   <country code="nu" default="Pacific/Niue" everutc="n">
    <id>Pacific/Niue</id>
   </country>
-  <country code="nz" default="Pacific/Auckland" everutc="n">
+  <country code="nz" default="Pacific/Auckland" defaultBoost="y" everutc="n">
    <id>Pacific/Auckland</id>
    <id>Pacific/Chatham</id>
   </country>
diff --git a/output_data/distro/distro.zip b/output_data/distro/distro.zip
index 326bff5..f1a6e43 100644
--- a/output_data/distro/distro.zip
+++ b/output_data/distro/distro.zip
Binary files differ
diff --git a/testing/data/test1/output_data/android/tzlookup.xml b/testing/data/test1/output_data/android/tzlookup.xml
index e366faf..f0e8007 100644
--- a/testing/data/test1/output_data/android/tzlookup.xml
+++ b/testing/data/test1/output_data/android/tzlookup.xml
@@ -40,7 +40,7 @@
    <id>Antarctica/Rothera</id>
    <id>Antarctica/Palmer</id>
   </country>
-  <country code="ar" default="America/Argentina/Buenos_Aires" everutc="n">
+  <country code="ar" default="America/Argentina/Buenos_Aires" defaultBoost="y" everutc="n">
    <id>America/Argentina/Buenos_Aires</id>
    <id notafter="687931200000">America/Argentina/Cordoba</id>
    <id notafter="1096171200000">America/Argentina/Salta</id>
@@ -219,7 +219,7 @@
   <country code="cm" default="Africa/Douala" everutc="n">
    <id>Africa/Douala</id>
   </country>
-  <country code="cn" default="Asia/Shanghai" everutc="n">
+  <country code="cn" default="Asia/Shanghai" defaultBoost="y" everutc="n">
    <id>Asia/Shanghai</id>
    <id>Asia/Urumqi</id>
   </country>
@@ -267,7 +267,7 @@
   <country code="dz" default="Africa/Algiers" everutc="n">
    <id>Africa/Algiers</id>
   </country>
-  <country code="ec" default="America/Guayaquil" everutc="n">
+  <country code="ec" default="America/Guayaquil" defaultBoost="y" everutc="n">
    <id>America/Guayaquil</id>
    <id>Pacific/Galapagos</id>
   </country>
@@ -621,7 +621,7 @@
   <country code="nu" default="Pacific/Niue" everutc="n">
    <id>Pacific/Niue</id>
   </country>
-  <country code="nz" default="Pacific/Auckland" everutc="n">
+  <country code="nz" default="Pacific/Auckland" defaultBoost="y" everutc="n">
    <id>Pacific/Auckland</id>
    <id>Pacific/Chatham</id>
   </country>
diff --git a/testing/data/test1/output_data/distro/distro.zip b/testing/data/test1/output_data/distro/distro.zip
index 6f5e12a..89c3c9c 100644
--- a/testing/data/test1/output_data/distro/distro.zip
+++ b/testing/data/test1/output_data/distro/distro.zip
Binary files differ
diff --git a/testing/data/test2/output_data/android/tzlookup.xml b/testing/data/test2/output_data/android/tzlookup.xml
index c5bd3e9..bbc984a 100644
--- a/testing/data/test2/output_data/android/tzlookup.xml
+++ b/testing/data/test2/output_data/android/tzlookup.xml
@@ -40,7 +40,7 @@
    <id>Antarctica/Rothera</id>
    <id>Antarctica/Palmer</id>
   </country>
-  <country code="ar" default="America/Argentina/Buenos_Aires" everutc="n">
+  <country code="ar" default="America/Argentina/Buenos_Aires" defaultBoost="y" everutc="n">
    <id>America/Argentina/Buenos_Aires</id>
    <id notafter="687931200000">America/Argentina/Cordoba</id>
    <id notafter="1096171200000">America/Argentina/Salta</id>
@@ -219,7 +219,7 @@
   <country code="cm" default="Africa/Douala" everutc="n">
    <id>Africa/Douala</id>
   </country>
-  <country code="cn" default="Asia/Shanghai" everutc="n">
+  <country code="cn" default="Asia/Shanghai" defaultBoost="y" everutc="n">
    <id>Asia/Shanghai</id>
    <id>Asia/Urumqi</id>
   </country>
@@ -267,7 +267,7 @@
   <country code="dz" default="Africa/Algiers" everutc="n">
    <id>Africa/Algiers</id>
   </country>
-  <country code="ec" default="America/Guayaquil" everutc="n">
+  <country code="ec" default="America/Guayaquil" defaultBoost="y" everutc="n">
    <id>America/Guayaquil</id>
    <id>Pacific/Galapagos</id>
   </country>
@@ -621,7 +621,7 @@
   <country code="nu" default="Pacific/Niue" everutc="n">
    <id>Pacific/Niue</id>
   </country>
-  <country code="nz" default="Pacific/Auckland" everutc="n">
+  <country code="nz" default="Pacific/Auckland" defaultBoost="y" everutc="n">
    <id>Pacific/Auckland</id>
    <id>Pacific/Chatham</id>
   </country>
diff --git a/testing/data/test2/output_data/distro/distro.zip b/testing/data/test2/output_data/distro/distro.zip
index 84d30ac..ff7dc36 100644
--- a/testing/data/test2/output_data/distro/distro.zip
+++ b/testing/data/test2/output_data/distro/distro.zip
Binary files differ
diff --git a/testing/data/test3/output_data/android/tzlookup.xml b/testing/data/test3/output_data/android/tzlookup.xml
index e366faf..f0e8007 100644
--- a/testing/data/test3/output_data/android/tzlookup.xml
+++ b/testing/data/test3/output_data/android/tzlookup.xml
@@ -40,7 +40,7 @@
    <id>Antarctica/Rothera</id>
    <id>Antarctica/Palmer</id>
   </country>
-  <country code="ar" default="America/Argentina/Buenos_Aires" everutc="n">
+  <country code="ar" default="America/Argentina/Buenos_Aires" defaultBoost="y" everutc="n">
    <id>America/Argentina/Buenos_Aires</id>
    <id notafter="687931200000">America/Argentina/Cordoba</id>
    <id notafter="1096171200000">America/Argentina/Salta</id>
@@ -219,7 +219,7 @@
   <country code="cm" default="Africa/Douala" everutc="n">
    <id>Africa/Douala</id>
   </country>
-  <country code="cn" default="Asia/Shanghai" everutc="n">
+  <country code="cn" default="Asia/Shanghai" defaultBoost="y" everutc="n">
    <id>Asia/Shanghai</id>
    <id>Asia/Urumqi</id>
   </country>
@@ -267,7 +267,7 @@
   <country code="dz" default="Africa/Algiers" everutc="n">
    <id>Africa/Algiers</id>
   </country>
-  <country code="ec" default="America/Guayaquil" everutc="n">
+  <country code="ec" default="America/Guayaquil" defaultBoost="y" everutc="n">
    <id>America/Guayaquil</id>
    <id>Pacific/Galapagos</id>
   </country>
@@ -621,7 +621,7 @@
   <country code="nu" default="Pacific/Niue" everutc="n">
    <id>Pacific/Niue</id>
   </country>
-  <country code="nz" default="Pacific/Auckland" everutc="n">
+  <country code="nz" default="Pacific/Auckland" defaultBoost="y" everutc="n">
    <id>Pacific/Auckland</id>
    <id>Pacific/Chatham</id>
   </country>
diff --git a/testing/data/test3/output_data/distro/distro.zip b/testing/data/test3/output_data/distro/distro.zip
index 4ae519d..333e914 100644
--- a/testing/data/test3/output_data/distro/distro.zip
+++ b/testing/data/test3/output_data/distro/distro.zip
Binary files differ
diff --git a/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupFile.java b/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupFile.java
index e2cc056..d29de56 100644
--- a/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupFile.java
+++ b/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupFile.java
@@ -47,10 +47,11 @@
     // <countryzones>
     private static final String COUNTRY_ZONES_ELEMENT = "countryzones";
 
-    // <country code="iso_code" default="olson_id" everutc="n|y">
+    // <country code="iso_code" default="olson_id" [defaultBoost="n|y"] everutc="n|y">
     private static final String COUNTRY_ELEMENT = "country";
     private static final String COUNTRY_CODE_ATTRIBUTE = "code";
     private static final String DEFAULT_ATTRIBUTE = "default";
+    private static final String DEFAULT_BOOST_ATTRIBUTE = "defaultBoost";
     private static final String EVER_USES_UTC_ATTRIBUTE = "everutc";
 
     // <id [picker="n|y"]>
@@ -79,7 +80,7 @@
          *       <id picker="n">America/Los_Angeles</id>
          *       ...
          *     </country>
-         *     <country code="gb" default="Europe/London" everutc="y">
+         *     <country code="gb" default="Europe/London" defaultBoost="y" everutc="y">
          *       <!-- 0:00 -->
          *       <id>Europe/London</id>
          *     </country>
@@ -164,12 +165,15 @@
 
         private final String isoCode;
         private final String defaultTimeZoneId;
+        private final boolean defaultTimeZoneBoost;
         private final boolean everUsesUtc;
         private final List<TimeZoneMapping> timeZoneIds = new ArrayList<>();
 
-        Country(String isoCode, String defaultTimeZoneId, boolean everUsesUtc) {
+        Country(String isoCode, String defaultTimeZoneId, boolean defaultTimeZoneBoost,
+                boolean everUsesUtc) {
             this.defaultTimeZoneId = defaultTimeZoneId;
             this.isoCode = isoCode;
+            this.defaultTimeZoneBoost = defaultTimeZoneBoost;
             this.everUsesUtc = everUsesUtc;
         }
 
@@ -182,6 +186,10 @@
             writer.writeStartElement(COUNTRY_ELEMENT);
             writer.writeAttribute(COUNTRY_CODE_ATTRIBUTE, country.isoCode);
             writer.writeAttribute(DEFAULT_ATTRIBUTE, country.defaultTimeZoneId);
+            if (country.defaultTimeZoneBoost) {
+                writer.writeAttribute(DEFAULT_BOOST_ATTRIBUTE,
+                        encodeBooleanAttribute(country.defaultTimeZoneBoost));
+            }
             writer.writeAttribute(EVER_USES_UTC_ATTRIBUTE, encodeBooleanAttribute(
                     country.everUsesUtc));
             for (TimeZoneMapping timeZoneId : country.timeZoneIds) {
diff --git a/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupGenerator.java b/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupGenerator.java
index 703006e..3d840d6 100644
--- a/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupGenerator.java
+++ b/tzlookup_generator/src/main/java/com/android/libcore/timezone/tzlookup/TzLookupGenerator.java
@@ -244,6 +244,8 @@
                 // No point in continuing.
                 return null;
             }
+            boolean defaultTimeZoneBoost =
+                    determineCountryDefaultTimeZoneBoost(countryIn, processingErrors);
 
             // Validate the default.
             if (!countryTimeZoneIds.contains(defaultTimeZoneId)) {
@@ -307,8 +309,8 @@
             }
 
             // Add the country to the output structure.
-            TzLookupFile.Country countryOut =
-                    new TzLookupFile.Country(isoCode, defaultTimeZoneId, everUsesUtc);
+            TzLookupFile.Country countryOut = new TzLookupFile.Country(
+                    isoCode, defaultTimeZoneId, defaultTimeZoneBoost, everUsesUtc);
 
             // Process each input time zone.
             for (CountryZonesFile.TimeZoneMapping timeZoneIn : timeZonesIn) {
@@ -378,6 +380,24 @@
     }
 
     /**
+     * Determines the defaultTimeZoneBoost value for the country.
+     */
+    private static boolean determineCountryDefaultTimeZoneBoost(
+            CountryZonesFile.Country countryIn, Errors processingErrorsOut) {
+        if (!countryIn.hasDefaultTimeZoneBoost()) {
+            return false;
+        }
+
+        boolean defaultTimeZoneBoost = countryIn.getDefaultTimeZoneBoost();
+        if (!countryIn.hasDefaultTimeZoneId() && defaultTimeZoneBoost) {
+            processingErrorsOut.addError(
+                    "defaultTimeZoneBoost is specified but defaultTimeZoneId is not explicit");
+        }
+
+        return defaultTimeZoneBoost;
+    }
+
+    /**
      * Returns true if any of the zones use UTC after the time specified.
      */
     private static boolean anyZonesUseUtc(List<String> timeZoneIds, long startTimeMillis) {
diff --git a/tzlookup_generator/src/main/proto/country_zones_file.proto b/tzlookup_generator/src/main/proto/country_zones_file.proto
index d21b921..6da1c29 100644
--- a/tzlookup_generator/src/main/proto/country_zones_file.proto
+++ b/tzlookup_generator/src/main/proto/country_zones_file.proto
@@ -29,7 +29,8 @@
 message Country {
     required string isoCode = 1;
     optional string defaultTimeZoneId = 2;
-    repeated TimeZoneMapping timeZoneMappings = 3;
+    optional bool defaultTimeZoneBoost = 3;
+    repeated TimeZoneMapping timeZoneMappings = 4;
 }
 
 message TimeZoneMapping {