Merge "Add "enhanced metrics collection" support"
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index ceab02f..aac23d8 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -103,6 +103,14 @@
     String SHELL_COMMAND_ENABLE_TELEPHONY_FALLBACK = "enable_telephony_fallback";
 
     /**
+     * A shell command that dumps a {@link
+     * com.android.server.timezonedetector.MetricsTimeZoneDetectorState} object to stdout for
+     * debugging.
+     * @hide
+     */
+    String SHELL_COMMAND_DUMP_METRICS = "dump_metrics";
+
+    /**
      * A shared utility method to create a {@link ManualTimeZoneSuggestion}.
      *
      * @hide
diff --git a/core/proto/android/app/time_zone_detector.proto b/core/proto/android/app/time_zone_detector.proto
index b33ca1d..b52aa82 100644
--- a/core/proto/android/app/time_zone_detector.proto
+++ b/core/proto/android/app/time_zone_detector.proto
@@ -32,16 +32,8 @@
 }
 
 /*
- * An obfuscated and simplified time zone suggestion for metrics use.
- *
- * The suggestion's time zone IDs (which relate to location) are obfuscated by
- * mapping them to an ordinal. When the ordinal is assigned consistently across
- * several objects (i.e. so the same time zone ID is always mapped to the same
- * ordinal), this allows comparisons between those objects. For example, we can
- * answer "did these two suggestions agree?", "does the suggestion match the
- * device's current time zone?", without leaking knowledge of location. Ordinals
- * are also significantly more compact than full IANA TZDB IDs, albeit highly
- * unstable and of limited use.
+ * A generic-form time zone suggestion for metrics use. Required to be a superset of the
+ * MetricsTimeZoneSuggestion proto defined in atoms.proto to ensure binary compatibility.
  */
 message MetricsTimeZoneSuggestion {
   option (android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -55,5 +47,24 @@
   // The ordinals for time zone(s) in the suggestion. Always empty for
   // UNCERTAIN, and can be empty for CERTAIN, for example when the device is in
   // a disputed area / on an ocean.
-  repeated uint32 time_zone_ordinals = 2;
+  //
+  // The suggestion's time zone IDs (which relate to location) are obfuscated by
+  // mapping them to an ordinal. When the ordinal is assigned consistently across
+  // several objects (i.e. so the same time zone ID is always mapped to the same
+  // ordinal), this allows comparisons between those objects. For example, we can
+  // answer "did these two suggestions agree?", "does the suggestion match the
+  // device's current time zone?", without leaking knowledge of location. Ordinals
+  // are also significantly more compact than full IANA TZDB IDs, albeit unstable
+  // and of limited use.
+  repeated int32 time_zone_ordinals = 2;
+
+  // The actual time zone ID(s) in the suggestion. Similar to time_zone_ordinals
+  // but contains the actual string IDs.
+  //
+  // This information is only captured / reported for some devices based on the
+  // value of a server side flag, i.e. it could be enabled for internal testers.
+  // Therefore the list can be empty even when time_zone_ordinals is populated.
+  //
+  // When enabled, see time_zone_ordinals for the expected number of values.
+  repeated string time_zone_ids = 3;
 }
diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java
index d24a3df..cf0e350 100644
--- a/services/core/java/com/android/server/timedetector/ServerFlags.java
+++ b/services/core/java/com/android/server/timedetector/ServerFlags.java
@@ -66,6 +66,7 @@
             KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE,
             KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE,
             KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED,
+            KEY_ENHANCED_METRICS_COLLECTION_ENABLED,
     })
     @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
     @Retention(RetentionPolicy.SOURCE)
@@ -156,12 +157,18 @@
             "time_detector_origin_priorities_override";
 
     /**
-     * The key to override the time detector lower bound configuration. The values is the number of
+     * The key to override the time detector lower bound configuration. The value is the number of
      * milliseconds since the beginning of the Unix epoch.
      */
     public static final @DeviceConfigKey String KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE =
             "time_detector_lower_bound_millis_override";
 
+    /**
+     * The key to allow extra metrics / telemetry information to be collected from internal testers.
+     */
+    public static final @DeviceConfigKey String KEY_ENHANCED_METRICS_COLLECTION_ENABLED =
+            "enhanced_metrics_collection_enabled";
+
     @GuardedBy("mListeners")
     private final ArrayMap<ConfigurationChangeListener, Set<String>> mListeners = new ArrayMap<>();
 
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index 65f077e..2291777 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -40,6 +40,7 @@
     private final boolean mTelephonyDetectionSupported;
     private final boolean mGeoDetectionSupported;
     private final boolean mTelephonyFallbackSupported;
+    private final boolean mEnhancedMetricsCollectionEnabled;
     private final boolean mAutoDetectionEnabledSetting;
     private final @UserIdInt int mUserId;
     private final boolean mUserConfigAllowed;
@@ -50,6 +51,7 @@
         mTelephonyDetectionSupported = builder.mTelephonyDetectionSupported;
         mGeoDetectionSupported = builder.mGeoDetectionSupported;
         mTelephonyFallbackSupported = builder.mTelephonyFallbackSupported;
+        mEnhancedMetricsCollectionEnabled = builder.mEnhancedMetricsCollectionEnabled;
         mAutoDetectionEnabledSetting = builder.mAutoDetectionEnabledSetting;
 
         mUserId = builder.mUserId;
@@ -81,6 +83,15 @@
         return mTelephonyFallbackSupported;
     }
 
+    /**
+     * Returns {@code true} if the device can collect / report extra metrics information for QA
+     * / testers. These metrics might involve logging more expensive or more revealing data that
+     * would not be collected from the set of public users.
+     */
+    public boolean isEnhancedMetricsCollectionEnabled() {
+        return mEnhancedMetricsCollectionEnabled;
+    }
+
     /** Returns the value of the auto time zone detection enabled setting. */
     public boolean getAutoDetectionEnabledSetting() {
         return mAutoDetectionEnabledSetting;
@@ -227,6 +238,7 @@
                 && mTelephonyDetectionSupported == that.mTelephonyDetectionSupported
                 && mGeoDetectionSupported == that.mGeoDetectionSupported
                 && mTelephonyFallbackSupported == that.mTelephonyFallbackSupported
+                && mEnhancedMetricsCollectionEnabled == that.mEnhancedMetricsCollectionEnabled
                 && mAutoDetectionEnabledSetting == that.mAutoDetectionEnabledSetting
                 && mLocationEnabledSetting == that.mLocationEnabledSetting
                 && mGeoDetectionEnabledSetting == that.mGeoDetectionEnabledSetting;
@@ -235,7 +247,8 @@
     @Override
     public int hashCode() {
         return Objects.hash(mUserId, mUserConfigAllowed, mTelephonyDetectionSupported,
-                mGeoDetectionSupported, mTelephonyFallbackSupported, mAutoDetectionEnabledSetting,
+                mGeoDetectionSupported, mTelephonyFallbackSupported,
+                mEnhancedMetricsCollectionEnabled, mAutoDetectionEnabledSetting,
                 mLocationEnabledSetting, mGeoDetectionEnabledSetting);
     }
 
@@ -247,6 +260,7 @@
                 + ", mTelephonyDetectionSupported=" + mTelephonyDetectionSupported
                 + ", mGeoDetectionSupported=" + mGeoDetectionSupported
                 + ", mTelephonyFallbackSupported=" + mTelephonyFallbackSupported
+                + ", mEnhancedMetricsCollectionEnabled=" + mEnhancedMetricsCollectionEnabled
                 + ", mAutoDetectionEnabledSetting=" + mAutoDetectionEnabledSetting
                 + ", mLocationEnabledSetting=" + mLocationEnabledSetting
                 + ", mGeoDetectionEnabledSetting=" + mGeoDetectionEnabledSetting
@@ -264,6 +278,7 @@
         private boolean mTelephonyDetectionSupported;
         private boolean mGeoDetectionSupported;
         private boolean mTelephonyFallbackSupported;
+        private boolean mEnhancedMetricsCollectionEnabled;
         private boolean mAutoDetectionEnabledSetting;
         private boolean mLocationEnabledSetting;
         private boolean mGeoDetectionEnabledSetting;
@@ -284,6 +299,7 @@
             this.mTelephonyDetectionSupported = toCopy.mTelephonyDetectionSupported;
             this.mTelephonyFallbackSupported = toCopy.mTelephonyFallbackSupported;
             this.mGeoDetectionSupported = toCopy.mGeoDetectionSupported;
+            this.mEnhancedMetricsCollectionEnabled = toCopy.mEnhancedMetricsCollectionEnabled;
             this.mAutoDetectionEnabledSetting = toCopy.mAutoDetectionEnabledSetting;
             this.mLocationEnabledSetting = toCopy.mLocationEnabledSetting;
             this.mGeoDetectionEnabledSetting = toCopy.mGeoDetectionEnabledSetting;
@@ -323,6 +339,14 @@
         }
 
         /**
+         * Sets the value for enhanced metrics collection.
+         */
+        public Builder setEnhancedMetricsCollectionEnabled(boolean enabled) {
+            mEnhancedMetricsCollectionEnabled = enabled;
+            return this;
+        }
+
+        /**
          * Sets the value of the automatic time zone detection enabled setting for this device.
          */
         public Builder setAutoDetectionEnabledSetting(boolean enabled) {
diff --git a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
index f156f8c..ecac267 100644
--- a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
+++ b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
@@ -34,11 +34,13 @@
  * A class that provides time zone detector state information for metrics.
  *
  * <p>
- * Regarding time zone ID ordinals:
+ * Regarding the use of time zone ID ordinals in metrics / telemetry:
  * <p>
- * We don't want to leak user location information by reporting time zone IDs. Instead, time zone
- * IDs are consistently identified within a given instance of this class by a numeric ID. This
- * allows comparison of IDs without revealing what those IDs are.
+ * For general metrics, we don't want to leak user location information by reporting time zone
+ * IDs. Instead, time zone IDs are consistently identified within a given instance of this class by
+ * a numeric ID (ordinal). This allows comparison of IDs without revealing what those IDs are.
+ * See {@link #isEnhancedMetricsCollectionEnabled()} for the setting that enables actual IDs to be
+ * collected.
  */
 public final class MetricsTimeZoneDetectorState {
 
@@ -54,6 +56,7 @@
 
     @NonNull private final ConfigurationInternal mConfigurationInternal;
     private final int mDeviceTimeZoneIdOrdinal;
+    @Nullable private final String mDeviceTimeZoneId;
     @Nullable private final MetricsTimeZoneSuggestion mLatestManualSuggestion;
     @Nullable private final MetricsTimeZoneSuggestion mLatestTelephonySuggestion;
     @Nullable private final MetricsTimeZoneSuggestion mLatestGeolocationSuggestion;
@@ -61,11 +64,13 @@
     private MetricsTimeZoneDetectorState(
             @NonNull ConfigurationInternal configurationInternal,
             int deviceTimeZoneIdOrdinal,
+            @Nullable String deviceTimeZoneId,
             @Nullable MetricsTimeZoneSuggestion latestManualSuggestion,
             @Nullable MetricsTimeZoneSuggestion latestTelephonySuggestion,
             @Nullable MetricsTimeZoneSuggestion latestGeolocationSuggestion) {
         mConfigurationInternal = Objects.requireNonNull(configurationInternal);
         mDeviceTimeZoneIdOrdinal = deviceTimeZoneIdOrdinal;
+        mDeviceTimeZoneId = deviceTimeZoneId;
         mLatestManualSuggestion = latestManualSuggestion;
         mLatestTelephonySuggestion = latestTelephonySuggestion;
         mLatestGeolocationSuggestion = latestGeolocationSuggestion;
@@ -83,18 +88,24 @@
             @Nullable TelephonyTimeZoneSuggestion latestTelephonySuggestion,
             @Nullable GeolocationTimeZoneSuggestion latestGeolocationSuggestion) {
 
+        boolean includeZoneIds = configurationInternal.isEnhancedMetricsCollectionEnabled();
+        String metricDeviceTimeZoneId = includeZoneIds ? deviceTimeZoneId : null;
         int deviceTimeZoneIdOrdinal =
                 tzIdOrdinalGenerator.ordinal(Objects.requireNonNull(deviceTimeZoneId));
         MetricsTimeZoneSuggestion latestCanonicalManualSuggestion =
-                createMetricsTimeZoneSuggestion(tzIdOrdinalGenerator, latestManualSuggestion);
+                createMetricsTimeZoneSuggestion(
+                        tzIdOrdinalGenerator, latestManualSuggestion, includeZoneIds);
         MetricsTimeZoneSuggestion latestCanonicalTelephonySuggestion =
-                createMetricsTimeZoneSuggestion(tzIdOrdinalGenerator, latestTelephonySuggestion);
+                createMetricsTimeZoneSuggestion(
+                        tzIdOrdinalGenerator, latestTelephonySuggestion, includeZoneIds);
         MetricsTimeZoneSuggestion latestCanonicalGeolocationSuggestion =
-                createMetricsTimeZoneSuggestion(tzIdOrdinalGenerator, latestGeolocationSuggestion);
+                createMetricsTimeZoneSuggestion(
+                        tzIdOrdinalGenerator, latestGeolocationSuggestion, includeZoneIds);
 
         return new MetricsTimeZoneDetectorState(
-                configurationInternal, deviceTimeZoneIdOrdinal, latestCanonicalManualSuggestion,
-                latestCanonicalTelephonySuggestion, latestCanonicalGeolocationSuggestion);
+                configurationInternal, deviceTimeZoneIdOrdinal, metricDeviceTimeZoneId,
+                latestCanonicalManualSuggestion, latestCanonicalTelephonySuggestion,
+                latestCanonicalGeolocationSuggestion);
     }
 
     /** Returns true if the device supports telephony time zone detection. */
@@ -112,6 +123,11 @@
         return mConfigurationInternal.isTelephonyFallbackSupported();
     }
 
+    /** Returns true if enhanced metric collection is enabled. */
+    public boolean isEnhancedMetricsCollectionEnabled() {
+        return mConfigurationInternal.isEnhancedMetricsCollectionEnabled();
+    }
+
     /** Returns true if user's location can be used generally. */
     public boolean getUserLocationEnabledSetting() {
         return mConfigurationInternal.getLocationEnabledSetting();
@@ -142,7 +158,7 @@
     }
 
     /**
-     * Returns the ordinal for the device's currently set time zone ID.
+     * Returns the ordinal for the device's current time zone ID.
      * See {@link MetricsTimeZoneDetectorState} for information about ordinals.
      */
     public int getDeviceTimeZoneIdOrdinal() {
@@ -150,6 +166,16 @@
     }
 
     /**
+     * Returns the device's current time zone ID. This will only be populated if {@link
+     * #isEnhancedMetricsCollectionEnabled()} is {@code true}. See {@link
+     * MetricsTimeZoneDetectorState} for details.
+     */
+    @Nullable
+    public String getDeviceTimeZoneId() {
+        return mDeviceTimeZoneId;
+    }
+
+    /**
      * Returns a canonical form of the last manual suggestion received.
      */
     @Nullable
@@ -183,6 +209,7 @@
         }
         MetricsTimeZoneDetectorState that = (MetricsTimeZoneDetectorState) o;
         return mDeviceTimeZoneIdOrdinal == that.mDeviceTimeZoneIdOrdinal
+                && Objects.equals(mDeviceTimeZoneId, that.mDeviceTimeZoneId)
                 && mConfigurationInternal.equals(that.mConfigurationInternal)
                 && Objects.equals(mLatestManualSuggestion, that.mLatestManualSuggestion)
                 && Objects.equals(mLatestTelephonySuggestion, that.mLatestTelephonySuggestion)
@@ -191,7 +218,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mConfigurationInternal, mDeviceTimeZoneIdOrdinal,
+        return Objects.hash(mConfigurationInternal, mDeviceTimeZoneIdOrdinal, mDeviceTimeZoneId,
                 mLatestManualSuggestion, mLatestTelephonySuggestion, mLatestGeolocationSuggestion);
     }
 
@@ -200,6 +227,7 @@
         return "MetricsTimeZoneDetectorState{"
                 + "mConfigurationInternal=" + mConfigurationInternal
                 + ", mDeviceTimeZoneIdOrdinal=" + mDeviceTimeZoneIdOrdinal
+                + ", mDeviceTimeZoneId=" + mDeviceTimeZoneId
                 + ", mLatestManualSuggestion=" + mLatestManualSuggestion
                 + ", mLatestTelephonySuggestion=" + mLatestTelephonySuggestion
                 + ", mLatestGeolocationSuggestion=" + mLatestGeolocationSuggestion
@@ -209,34 +237,40 @@
     @Nullable
     private static MetricsTimeZoneSuggestion createMetricsTimeZoneSuggestion(
             @NonNull OrdinalGenerator<String> zoneIdOrdinalGenerator,
-            @NonNull ManualTimeZoneSuggestion manualSuggestion) {
+            @NonNull ManualTimeZoneSuggestion manualSuggestion,
+            boolean includeFullZoneIds) {
         if (manualSuggestion == null) {
             return null;
         }
 
-        int zoneIdOrdinal = zoneIdOrdinalGenerator.ordinal(manualSuggestion.getZoneId());
-        return MetricsTimeZoneSuggestion.createCertain(
-                new int[] { zoneIdOrdinal });
+        String suggestionZoneId = manualSuggestion.getZoneId();
+        String[] metricZoneIds = includeFullZoneIds ? new String[] { suggestionZoneId } : null;
+        int[] zoneIdOrdinals = new int[] { zoneIdOrdinalGenerator.ordinal(suggestionZoneId) };
+        return MetricsTimeZoneSuggestion.createCertain(metricZoneIds, zoneIdOrdinals);
     }
 
     @Nullable
     private static MetricsTimeZoneSuggestion createMetricsTimeZoneSuggestion(
             @NonNull OrdinalGenerator<String> zoneIdOrdinalGenerator,
-            @NonNull TelephonyTimeZoneSuggestion telephonySuggestion) {
+            @NonNull TelephonyTimeZoneSuggestion telephonySuggestion,
+            boolean includeFullZoneIds) {
         if (telephonySuggestion == null) {
             return null;
         }
-        if (telephonySuggestion.getZoneId() == null) {
+        String suggestionZoneId = telephonySuggestion.getZoneId();
+        if (suggestionZoneId == null) {
             return MetricsTimeZoneSuggestion.createUncertain();
         }
-        int zoneIdOrdinal = zoneIdOrdinalGenerator.ordinal(telephonySuggestion.getZoneId());
-        return MetricsTimeZoneSuggestion.createCertain(new int[] { zoneIdOrdinal });
+        String[] metricZoneIds = includeFullZoneIds ? new String[] { suggestionZoneId } : null;
+        int[] zoneIdOrdinals = new int[] { zoneIdOrdinalGenerator.ordinal(suggestionZoneId) };
+        return MetricsTimeZoneSuggestion.createCertain(metricZoneIds, zoneIdOrdinals);
     }
 
     @Nullable
     private static MetricsTimeZoneSuggestion createMetricsTimeZoneSuggestion(
             @NonNull OrdinalGenerator<String> zoneIdOrdinalGenerator,
-            @Nullable GeolocationTimeZoneSuggestion geolocationSuggestion) {
+            @Nullable GeolocationTimeZoneSuggestion geolocationSuggestion,
+            boolean includeFullZoneIds) {
         if (geolocationSuggestion == null) {
             return null;
         }
@@ -245,7 +279,9 @@
         if (zoneIds == null) {
             return MetricsTimeZoneSuggestion.createUncertain();
         }
-        return MetricsTimeZoneSuggestion.createCertain(zoneIdOrdinalGenerator.ordinals(zoneIds));
+        String[] metricZoneIds = includeFullZoneIds ? zoneIds.toArray(new String[0]) : null;
+        int[] zoneIdOrdinals = zoneIdOrdinalGenerator.ordinals(zoneIds);
+        return MetricsTimeZoneSuggestion.createCertain(metricZoneIds, zoneIdOrdinals);
     }
 
     /**
@@ -254,33 +290,49 @@
      * MetricsTimeZoneSuggestion proto definition.
      */
     public static final class MetricsTimeZoneSuggestion {
-        @Nullable
-        private final int[] mZoneIdOrdinals;
+        @Nullable private final String[] mZoneIds;
+        @Nullable private final int[] mZoneIdOrdinals;
 
-        MetricsTimeZoneSuggestion(@Nullable int[] zoneIdOrdinals) {
+        private MetricsTimeZoneSuggestion(
+                @Nullable String[] zoneIds, @Nullable int[] zoneIdOrdinals) {
+            mZoneIds = zoneIds;
             mZoneIdOrdinals = zoneIdOrdinals;
         }
 
         @NonNull
         static MetricsTimeZoneSuggestion createUncertain() {
-            return new MetricsTimeZoneSuggestion(null);
+            return new MetricsTimeZoneSuggestion(null, null);
         }
 
         @NonNull
         static MetricsTimeZoneSuggestion createCertain(
-                @NonNull int[] zoneIdOrdinals) {
-            return new MetricsTimeZoneSuggestion(zoneIdOrdinals);
+                @Nullable String[] zoneIds, @NonNull int[] zoneIdOrdinals) {
+            return new MetricsTimeZoneSuggestion(zoneIds, zoneIdOrdinals);
         }
 
         public boolean isCertain() {
             return mZoneIdOrdinals != null;
         }
 
+        /**
+         * Returns ordinals for the time zone IDs contained in the suggestion.
+         * See {@link MetricsTimeZoneDetectorState} for information about ordinals.
+         */
         @Nullable
         public int[] getZoneIdOrdinals() {
             return mZoneIdOrdinals;
         }
 
+        /**
+         * Returns the time zone IDs contained in the suggestion. This will only be populated if
+         * {@link #isEnhancedMetricsCollectionEnabled()} is {@code true}. See {@link
+         * MetricsTimeZoneDetectorState} for details.
+         */
+        @Nullable
+        public String[] getZoneIds() {
+            return mZoneIds;
+        }
+
         @Override
         public boolean equals(Object o) {
             if (this == o) {
@@ -290,18 +342,22 @@
                 return false;
             }
             MetricsTimeZoneSuggestion that = (MetricsTimeZoneSuggestion) o;
-            return Arrays.equals(mZoneIdOrdinals, that.mZoneIdOrdinals);
+            return Arrays.equals(mZoneIdOrdinals, that.mZoneIdOrdinals)
+                    && Arrays.equals(mZoneIds, that.mZoneIds);
         }
 
         @Override
         public int hashCode() {
-            return Arrays.hashCode(mZoneIdOrdinals);
+            int result = Arrays.hashCode(mZoneIds);
+            result = 31 * result + Arrays.hashCode(mZoneIdOrdinals);
+            return result;
         }
 
         @Override
         public String toString() {
             return "MetricsTimeZoneSuggestion{"
                     + "mZoneIdOrdinals=" + Arrays.toString(mZoneIdOrdinals)
+                    + ", mZoneIds=" + Arrays.toString(mZoneIds)
                     + '}';
         }
     }
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
index 02ea433..4612f65 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
@@ -62,6 +62,7 @@
     private static final Set<String> CONFIGURATION_INTERNAL_SERVER_FLAGS_KEYS_TO_WATCH =
             Collections.unmodifiableSet(new ArraySet<>(new String[] {
                     ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
+                    ServerFlags.KEY_ENHANCED_METRICS_COLLECTION_ENABLED,
                     ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
                     ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
                     ServerFlags.KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED,
@@ -296,6 +297,7 @@
                         isTelephonyTimeZoneDetectionFeatureSupported())
                 .setGeoDetectionFeatureSupported(isGeoTimeZoneDetectionFeatureSupported())
                 .setTelephonyFallbackSupported(isTelephonyFallbackSupported())
+                .setEnhancedMetricsCollectionEnabled(isEnhancedMetricsCollectionEnabled())
                 .setAutoDetectionEnabledSetting(getAutoDetectionEnabledSetting())
                 .setUserConfigAllowed(isUserConfigAllowed(userId))
                 .setLocationEnabledSetting(getLocationEnabledSetting(userId))
@@ -400,6 +402,17 @@
                 defaultEnabled);
     }
 
+    /**
+     * Returns {@code true} if extra metrics / telemetry information can be collected. Used for
+     * internal testers.
+     */
+    private boolean isEnhancedMetricsCollectionEnabled() {
+        final boolean defaultEnabled = false;
+        return mServerFlags.getBoolean(
+                ServerFlags.KEY_ENHANCED_METRICS_COLLECTION_ENABLED,
+                defaultEnabled);
+    }
+
     @Override
     @NonNull
     public synchronized String getPrimaryLocationTimeZoneProviderPackageName() {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 14784cf..f75608e 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -364,6 +364,13 @@
         }
     }
 
+    @NonNull
+    MetricsTimeZoneDetectorState generateMetricsState() {
+        enforceManageTimeZoneDetectorPermission();
+
+        return mTimeZoneDetectorStrategy.generateMetricsState();
+    }
+
     @Override
     protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
             @Nullable String[] args) {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
index 2b912ad..8535b3d 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.timezonedetector;
 
+import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_DUMP_METRICS;
 import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_ENABLE_TELEPHONY_FALLBACK;
 import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED;
 import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_GEO_DETECTION_ENABLED;
@@ -28,6 +29,7 @@
 import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SUGGEST_TELEPHONY_TIME_ZONE;
 import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME;
 
+import static com.android.server.timedetector.ServerFlags.KEY_ENHANCED_METRICS_COLLECTION_ENABLED;
 import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED;
 import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT;
 import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE;
@@ -80,6 +82,8 @@
                 return runSuggestTelephonyTimeZone();
             case SHELL_COMMAND_ENABLE_TELEPHONY_FALLBACK:
                 return runEnableTelephonyFallback();
+            case SHELL_COMMAND_DUMP_METRICS:
+                return runDumpMetrics();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -168,14 +172,22 @@
             pw.println("Suggestion " + suggestion + " injected.");
             return 0;
         } catch (RuntimeException e) {
-            pw.println(e.toString());
+            pw.println(e);
             return 1;
         }
     }
 
     private int runEnableTelephonyFallback() {
         mInterface.enableTelephonyFallback();
-        return 1;
+        return 0;
+    }
+
+    private int runDumpMetrics() {
+        final PrintWriter pw = getOutPrintWriter();
+        MetricsTimeZoneDetectorState metricsState = mInterface.generateMetricsState();
+        pw.println("MetricsTimeZoneDetectorState:");
+        pw.println(metricsState.toString());
+        return 0;
     }
 
     @Override
@@ -208,10 +220,10 @@
         pw.println();
         pw.printf("  %s <geolocation suggestion opts>\n",
                 SHELL_COMMAND_SUGGEST_GEO_LOCATION_TIME_ZONE);
-        pw.printf("  %s <manual suggestion opts>\n",
-                SHELL_COMMAND_SUGGEST_MANUAL_TIME_ZONE);
-        pw.printf("  %s <telephony suggestion opts>\n",
-                SHELL_COMMAND_SUGGEST_TELEPHONY_TIME_ZONE);
+        pw.printf("  %s <manual suggestion opts>\n", SHELL_COMMAND_SUGGEST_MANUAL_TIME_ZONE);
+        pw.printf("  %s <telephony suggestion opts>\n", SHELL_COMMAND_SUGGEST_TELEPHONY_TIME_ZONE);
+        pw.printf("  %s\n", SHELL_COMMAND_DUMP_METRICS);
+        pw.printf("    Dumps the service metrics to stdout for inspection.\n");
         pw.println();
         GeolocationTimeZoneSuggestion.printCommandLineOpts(pw);
         pw.println();
@@ -235,6 +247,8 @@
         pw.printf("  %s\n", KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED);
         pw.printf("    Used to enable / disable support for telephony detection fallback. Also see"
                 + " the %s command.\n", SHELL_COMMAND_ENABLE_TELEPHONY_FALLBACK);
+        pw.printf("  %s\n", KEY_ENHANCED_METRICS_COLLECTION_ENABLED);
+        pw.printf("    Used to increase the detail of metrics collected / reported.\n");
         pw.println();
         pw.printf("[*] To be enabled, the user must still have location = on / auto time zone"
                 + " detection = on.\n");
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
index 6ee6020c..a963785 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -49,6 +49,7 @@
                 .setTelephonyDetectionFeatureSupported(true)
                 .setGeoDetectionFeatureSupported(true)
                 .setTelephonyFallbackSupported(false)
+                .setEnhancedMetricsCollectionEnabled(false)
                 .setAutoDetectionEnabledSetting(true)
                 .setLocationEnabledSetting(true)
                 .setGeoDetectionEnabledSetting(true)
@@ -112,6 +113,7 @@
                 .setTelephonyDetectionFeatureSupported(true)
                 .setGeoDetectionFeatureSupported(true)
                 .setTelephonyFallbackSupported(false)
+                .setEnhancedMetricsCollectionEnabled(false)
                 .setAutoDetectionEnabledSetting(true)
                 .setLocationEnabledSetting(true)
                 .setGeoDetectionEnabledSetting(true)
@@ -177,6 +179,7 @@
                 .setTelephonyDetectionFeatureSupported(false)
                 .setGeoDetectionFeatureSupported(false)
                 .setTelephonyFallbackSupported(false)
+                .setEnhancedMetricsCollectionEnabled(false)
                 .setAutoDetectionEnabledSetting(true)
                 .setLocationEnabledSetting(true)
                 .setGeoDetectionEnabledSetting(true)
@@ -240,6 +243,7 @@
                 .setTelephonyDetectionFeatureSupported(true)
                 .setGeoDetectionFeatureSupported(false)
                 .setTelephonyFallbackSupported(false)
+                .setEnhancedMetricsCollectionEnabled(false)
                 .setAutoDetectionEnabledSetting(true)
                 .setLocationEnabledSetting(true)
                 .setGeoDetectionEnabledSetting(true)
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java
new file mode 100644
index 0000000..9029ac5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 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.server.timezonedetector;
+
+import static com.android.server.timezonedetector.MetricsTimeZoneDetectorState.DETECTION_MODE_GEO;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.annotation.ElapsedRealtimeLong;
+import android.annotation.UserIdInt;
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
+
+import com.android.server.timezonedetector.MetricsTimeZoneDetectorState.MetricsTimeZoneSuggestion;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.function.Function;
+
+/** Tests for {@link MetricsTimeZoneDetectorState}. */
+public class MetricsTimeZoneDetectorStateTest {
+
+    private static final @UserIdInt int ARBITRARY_USER_ID = 1;
+    private static final @ElapsedRealtimeLong long ARBITRARY_ELAPSED_REALTIME_MILLIS = 1234L;
+    private static final String DEVICE_TIME_ZONE_ID = "DeviceTimeZoneId";
+
+    private static final ManualTimeZoneSuggestion MANUAL_TIME_ZONE_SUGGESTION =
+            new ManualTimeZoneSuggestion("ManualTimeZoneId");
+
+    private static final TelephonyTimeZoneSuggestion TELEPHONY_TIME_ZONE_SUGGESTION =
+            new TelephonyTimeZoneSuggestion.Builder(0)
+                    .setZoneId("TelephonyZoneId")
+                    .setMatchType(TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                    .setQuality(TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE)
+                    .build();
+
+    private static final GeolocationTimeZoneSuggestion GEOLOCATION_TIME_ZONE_SUGGESTION =
+            GeolocationTimeZoneSuggestion.createCertainSuggestion(
+                    ARBITRARY_ELAPSED_REALTIME_MILLIS,
+                    Arrays.asList("GeoTimeZoneId1", "GeoTimeZoneId2"));
+
+    private final OrdinalGenerator<String> mOrdinalGenerator =
+            new OrdinalGenerator<>(Function.identity());
+
+    @Test
+    public void enhancedMetricsCollectionEnabled() {
+        final boolean enhancedMetricsCollectionEnabled = true;
+        ConfigurationInternal configurationInternal =
+                createConfigurationInternal(enhancedMetricsCollectionEnabled);
+
+        // Create the object.
+        MetricsTimeZoneDetectorState metricsTimeZoneDetectorState =
+                MetricsTimeZoneDetectorState.create(mOrdinalGenerator, configurationInternal,
+                        DEVICE_TIME_ZONE_ID, MANUAL_TIME_ZONE_SUGGESTION,
+                        TELEPHONY_TIME_ZONE_SUGGESTION, GEOLOCATION_TIME_ZONE_SUGGESTION);
+
+        // Assert the content.
+        assertCommonConfiguration(configurationInternal, metricsTimeZoneDetectorState);
+
+        assertEquals(DEVICE_TIME_ZONE_ID, metricsTimeZoneDetectorState.getDeviceTimeZoneId());
+        MetricsTimeZoneSuggestion expectedManualSuggestion =
+                MetricsTimeZoneSuggestion.createCertain(
+                        new String[] { MANUAL_TIME_ZONE_SUGGESTION.getZoneId() },
+                        new int[] { 1 });
+        assertEquals(expectedManualSuggestion,
+                metricsTimeZoneDetectorState.getLatestManualSuggestion());
+
+        MetricsTimeZoneSuggestion expectedTelephonySuggestion =
+                MetricsTimeZoneSuggestion.createCertain(
+                        new String[] { TELEPHONY_TIME_ZONE_SUGGESTION.getZoneId() },
+                        new int[] { 2 });
+        assertEquals(expectedTelephonySuggestion,
+                metricsTimeZoneDetectorState.getLatestTelephonySuggestion());
+
+        MetricsTimeZoneSuggestion expectedGeoSuggestion =
+                MetricsTimeZoneSuggestion.createCertain(
+                        GEOLOCATION_TIME_ZONE_SUGGESTION.getZoneIds().toArray(new String[0]),
+                        new int[] { 3, 4 });
+        assertEquals(expectedGeoSuggestion,
+                metricsTimeZoneDetectorState.getLatestGeolocationSuggestion());
+    }
+
+    @Test
+    public void enhancedMetricsCollectionDisabled() {
+        final boolean enhancedMetricsCollectionEnabled = false;
+        ConfigurationInternal configurationInternal =
+                createConfigurationInternal(enhancedMetricsCollectionEnabled);
+
+        // Create the object.
+        MetricsTimeZoneDetectorState metricsTimeZoneDetectorState =
+                MetricsTimeZoneDetectorState.create(mOrdinalGenerator, configurationInternal,
+                        DEVICE_TIME_ZONE_ID, MANUAL_TIME_ZONE_SUGGESTION,
+                        TELEPHONY_TIME_ZONE_SUGGESTION, GEOLOCATION_TIME_ZONE_SUGGESTION);
+
+        // Assert the content.
+        assertCommonConfiguration(configurationInternal, metricsTimeZoneDetectorState);
+
+        // When enhancedMetricsCollectionEnabled == false, no time zone IDs should be included.
+        assertNull(metricsTimeZoneDetectorState.getDeviceTimeZoneId());
+        final String[] omittedZoneIds = null;
+
+        MetricsTimeZoneSuggestion expectedManualSuggestion =
+                MetricsTimeZoneSuggestion.createCertain(
+                        omittedZoneIds,
+                        new int[] { 1 });
+        assertEquals(expectedManualSuggestion,
+                metricsTimeZoneDetectorState.getLatestManualSuggestion());
+
+        MetricsTimeZoneSuggestion expectedTelephonySuggestion =
+                MetricsTimeZoneSuggestion.createCertain(
+                        omittedZoneIds,
+                        new int[] { 2 });
+        assertEquals(expectedTelephonySuggestion,
+                metricsTimeZoneDetectorState.getLatestTelephonySuggestion());
+
+        MetricsTimeZoneSuggestion expectedGeoSuggestion =
+                MetricsTimeZoneSuggestion.createCertain(
+                        omittedZoneIds,
+                        new int[] { 3, 4 });
+        assertEquals(expectedGeoSuggestion,
+                metricsTimeZoneDetectorState.getLatestGeolocationSuggestion());
+    }
+
+    private static void assertCommonConfiguration(ConfigurationInternal configurationInternal,
+            MetricsTimeZoneDetectorState metricsTimeZoneDetectorState) {
+        assertEquals(configurationInternal.isTelephonyDetectionSupported(),
+                metricsTimeZoneDetectorState.isTelephonyDetectionSupported());
+        assertEquals(configurationInternal.isGeoDetectionSupported(),
+                metricsTimeZoneDetectorState.isGeoDetectionSupported());
+        assertEquals(configurationInternal.getAutoDetectionEnabledSetting(),
+                metricsTimeZoneDetectorState.getAutoDetectionEnabledSetting());
+        assertEquals(configurationInternal.getLocationEnabledSetting(),
+                metricsTimeZoneDetectorState.getUserLocationEnabledSetting());
+        assertEquals(configurationInternal.getGeoDetectionEnabledSetting(),
+                metricsTimeZoneDetectorState.getGeoDetectionEnabledSetting());
+        assertEquals(configurationInternal.isEnhancedMetricsCollectionEnabled(),
+                metricsTimeZoneDetectorState.isEnhancedMetricsCollectionEnabled());
+        assertEquals(0, metricsTimeZoneDetectorState.getDeviceTimeZoneIdOrdinal());
+        assertEquals(DETECTION_MODE_GEO, metricsTimeZoneDetectorState.getDetectionMode());
+    }
+
+    private static ConfigurationInternal createConfigurationInternal(
+            boolean enhancedMetricsCollectionEnabled) {
+        return new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+                .setUserConfigAllowed(true)
+                .setTelephonyDetectionFeatureSupported(true)
+                .setGeoDetectionFeatureSupported(true)
+                .setEnhancedMetricsCollectionEnabled(enhancedMetricsCollectionEnabled)
+                .setAutoDetectionEnabledSetting(true)
+                .setLocationEnabledSetting(true)
+                .setGeoDetectionEnabledSetting(true)
+                .build();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index 193b2e3..e0e5ba0 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -379,6 +379,7 @@
                 .setTelephonyDetectionFeatureSupported(true)
                 .setGeoDetectionFeatureSupported(true)
                 .setTelephonyFallbackSupported(false)
+                .setEnhancedMetricsCollectionEnabled(false)
                 .setUserConfigAllowed(true)
                 .setAutoDetectionEnabledSetting(autoDetectionEnabled)
                 .setLocationEnabledSetting(geoDetectionEnabled)
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index ef1b4f5..27f7814 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -87,10 +87,11 @@
 
     private static final ConfigurationInternal CONFIG_USER_RESTRICTED_AUTO_DISABLED =
             new ConfigurationInternal.Builder(USER_ID)
-                    .setUserConfigAllowed(false)
                     .setTelephonyDetectionFeatureSupported(true)
                     .setGeoDetectionFeatureSupported(true)
                     .setTelephonyFallbackSupported(false)
+                    .setEnhancedMetricsCollectionEnabled(false)
+                    .setUserConfigAllowed(false)
                     .setAutoDetectionEnabledSetting(false)
                     .setLocationEnabledSetting(true)
                     .setGeoDetectionEnabledSetting(false)
@@ -98,10 +99,11 @@
 
     private static final ConfigurationInternal CONFIG_USER_RESTRICTED_AUTO_ENABLED =
             new ConfigurationInternal.Builder(USER_ID)
-                    .setUserConfigAllowed(false)
                     .setTelephonyDetectionFeatureSupported(true)
                     .setGeoDetectionFeatureSupported(true)
                     .setTelephonyFallbackSupported(false)
+                    .setEnhancedMetricsCollectionEnabled(false)
+                    .setUserConfigAllowed(false)
                     .setAutoDetectionEnabledSetting(true)
                     .setLocationEnabledSetting(true)
                     .setGeoDetectionEnabledSetting(true)
@@ -109,10 +111,11 @@
 
     private static final ConfigurationInternal CONFIG_AUTO_DETECT_NOT_SUPPORTED =
             new ConfigurationInternal.Builder(USER_ID)
-                    .setUserConfigAllowed(true)
                     .setTelephonyDetectionFeatureSupported(false)
                     .setGeoDetectionFeatureSupported(false)
                     .setTelephonyFallbackSupported(false)
+                    .setEnhancedMetricsCollectionEnabled(false)
+                    .setUserConfigAllowed(true)
                     .setAutoDetectionEnabledSetting(false)
                     .setLocationEnabledSetting(true)
                     .setGeoDetectionEnabledSetting(false)
@@ -120,10 +123,11 @@
 
     private static final ConfigurationInternal CONFIG_AUTO_DISABLED_GEO_DISABLED =
             new ConfigurationInternal.Builder(USER_ID)
-                    .setUserConfigAllowed(true)
                     .setTelephonyDetectionFeatureSupported(true)
                     .setGeoDetectionFeatureSupported(true)
                     .setTelephonyFallbackSupported(false)
+                    .setEnhancedMetricsCollectionEnabled(false)
+                    .setUserConfigAllowed(true)
                     .setAutoDetectionEnabledSetting(false)
                     .setLocationEnabledSetting(true)
                     .setGeoDetectionEnabledSetting(false)
@@ -134,6 +138,7 @@
                     .setTelephonyDetectionFeatureSupported(true)
                     .setGeoDetectionFeatureSupported(true)
                     .setTelephonyFallbackSupported(false)
+                    .setEnhancedMetricsCollectionEnabled(false)
                     .setUserConfigAllowed(true)
                     .setAutoDetectionEnabledSetting(true)
                     .setLocationEnabledSetting(true)
@@ -145,6 +150,7 @@
                     .setTelephonyDetectionFeatureSupported(true)
                     .setGeoDetectionFeatureSupported(true)
                     .setTelephonyFallbackSupported(false)
+                    .setEnhancedMetricsCollectionEnabled(false)
                     .setUserConfigAllowed(true)
                     .setAutoDetectionEnabledSetting(true)
                     .setLocationEnabledSetting(true)
@@ -955,8 +961,20 @@
     }
 
     @Test
-    public void testGenerateMetricsState() {
-        ConfigurationInternal expectedInternalConfig = CONFIG_AUTO_DISABLED_GEO_DISABLED;
+    public void testGenerateMetricsState_enhancedMetricsCollection() {
+        testGenerateMetricsState(true);
+    }
+
+    @Test
+    public void testGenerateMetricsState_notEnhancedMetricsCollection() {
+        testGenerateMetricsState(false);
+    }
+
+    private void testGenerateMetricsState(boolean enhancedMetricsCollection) {
+        ConfigurationInternal expectedInternalConfig =
+                new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED_GEO_DISABLED)
+                        .setEnhancedMetricsCollectionEnabled(enhancedMetricsCollection)
+                        .build();
         String expectedDeviceTimeZoneId = "InitialZoneId";
 
         Script script = new Script()
@@ -1028,7 +1046,7 @@
                         tzIdOrdinalGenerator, expectedInternalConfig, expectedDeviceTimeZoneId,
                         expectedManualSuggestion, expectedTelephonySuggestion,
                         expectedGeolocationTimeZoneSuggestion);
-        // Rely on MetricsTimeZoneDetectorState.equals() for time zone ID ordinal comparisons.
+        // Rely on MetricsTimeZoneDetectorState.equals() for time zone ID / ID ordinal comparisons.
         assertEquals(expectedState, actualState);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
index a2df3130..9d01310 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
@@ -47,6 +47,7 @@
                 .setTelephonyDetectionFeatureSupported(true)
                 .setGeoDetectionFeatureSupported(true)
                 .setTelephonyFallbackSupported(false)
+                .setEnhancedMetricsCollectionEnabled(false)
                 .setAutoDetectionEnabledSetting(true)
                 .setLocationEnabledSetting(true)
                 .setGeoDetectionEnabledSetting(geoDetectionEnabledSetting)