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)