Merge "Consider equivalent time zone IDs as equal in metrics." into sc-dev am: 327db7857d am: 611f4422ae
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14353365 Change-Id: I25df7154b909dc9aefce8edc64b802da8730ab8f
This commit is contained in:
@@ -89,8 +89,6 @@ public final class MetricsTimeZoneDetectorState {
|
|||||||
@Nullable TelephonyTimeZoneSuggestion latestTelephonySuggestion,
|
@Nullable TelephonyTimeZoneSuggestion latestTelephonySuggestion,
|
||||||
@Nullable GeolocationTimeZoneSuggestion latestGeolocationSuggestion) {
|
@Nullable GeolocationTimeZoneSuggestion latestGeolocationSuggestion) {
|
||||||
|
|
||||||
// TODO(b/172934905) Add logic to canonicalize the time zone IDs to Android's preferred IDs
|
|
||||||
// so that the ordinals will match even when the ID is not identical, just equivalent.
|
|
||||||
int deviceTimeZoneIdOrdinal =
|
int deviceTimeZoneIdOrdinal =
|
||||||
tzIdOrdinalGenerator.ordinal(Objects.requireNonNull(deviceTimeZoneId));
|
tzIdOrdinalGenerator.ordinal(Objects.requireNonNull(deviceTimeZoneId));
|
||||||
MetricsTimeZoneSuggestion latestObfuscatedManualSuggestion =
|
MetricsTimeZoneSuggestion latestObfuscatedManualSuggestion =
|
||||||
|
|||||||
@@ -15,9 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.server.timezonedetector;
|
package com.android.server.timezonedetector;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper class that turns a set of objects into ordinal values, i.e. each object is offered
|
* A helper class that turns a set of objects into ordinal values, i.e. each object is offered
|
||||||
@@ -30,11 +33,19 @@ import java.util.List;
|
|||||||
class OrdinalGenerator<T> {
|
class OrdinalGenerator<T> {
|
||||||
private final ArraySet<T> mKnownIds = new ArraySet<>();
|
private final ArraySet<T> mKnownIds = new ArraySet<>();
|
||||||
|
|
||||||
|
private final @NonNull Function<T, T> mCanonicalizationFunction;
|
||||||
|
|
||||||
|
OrdinalGenerator(@NonNull Function<T, T> canonicalizationFunction) {
|
||||||
|
mCanonicalizationFunction = Objects.requireNonNull(canonicalizationFunction);
|
||||||
|
}
|
||||||
|
|
||||||
int ordinal(T object) {
|
int ordinal(T object) {
|
||||||
int ordinal = mKnownIds.indexOf(object);
|
T canonical = mCanonicalizationFunction.apply(object);
|
||||||
|
|
||||||
|
int ordinal = mKnownIds.indexOf(canonical);
|
||||||
if (ordinal < 0) {
|
if (ordinal < 0) {
|
||||||
ordinal = mKnownIds.size();
|
ordinal = mKnownIds.size();
|
||||||
mKnownIds.add(object);
|
mKnownIds.add(canonical);
|
||||||
}
|
}
|
||||||
return ordinal;
|
return ordinal;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.android.i18n.timezone.TimeZoneFinder;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns preferred time zone ID if {@code timeZoneId} was deprecated. For example, returns
|
||||||
|
* America/Nuuk for America/Godthab.
|
||||||
|
*/
|
||||||
|
final class TimeZoneCanonicalizer implements Function<String, String> {
|
||||||
|
@Override
|
||||||
|
public String apply(String timeZoneId) {
|
||||||
|
String canonicialZoneId = TimeZoneFinder.getInstance().getCountryZonesFinder()
|
||||||
|
.findCanonicalTimeZoneId(timeZoneId);
|
||||||
|
|
||||||
|
return canonicialZoneId == null ? timeZoneId : canonicialZoneId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -383,7 +383,8 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
|||||||
bestQualifiedTelephonySuggestion == null
|
bestQualifiedTelephonySuggestion == null
|
||||||
? null : bestQualifiedTelephonySuggestion.suggestion;
|
? null : bestQualifiedTelephonySuggestion.suggestion;
|
||||||
// A new generator is created each time: we don't want / require consistency.
|
// A new generator is created each time: we don't want / require consistency.
|
||||||
OrdinalGenerator<String> tzIdOrdinalGenerator = new OrdinalGenerator<>();
|
OrdinalGenerator<String> tzIdOrdinalGenerator =
|
||||||
|
new OrdinalGenerator<>(new TimeZoneCanonicalizer());
|
||||||
return MetricsTimeZoneDetectorState.create(
|
return MetricsTimeZoneDetectorState.create(
|
||||||
tzIdOrdinalGenerator,
|
tzIdOrdinalGenerator,
|
||||||
getConfigurationInternal(currentUserId),
|
getConfigurationInternal(currentUserId),
|
||||||
|
|||||||
@@ -25,13 +25,14 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class OrdinalGeneratorTest {
|
public class OrdinalGeneratorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOrdinal() {
|
public void testOrdinal_withIdentityFunction() {
|
||||||
OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>();
|
OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>(Function.identity());
|
||||||
int oneOrd = ordinalGenerator.ordinal("One");
|
int oneOrd = ordinalGenerator.ordinal("One");
|
||||||
int twoOrd = ordinalGenerator.ordinal("Two");
|
int twoOrd = ordinalGenerator.ordinal("Two");
|
||||||
assertNotEquals(oneOrd, twoOrd);
|
assertNotEquals(oneOrd, twoOrd);
|
||||||
@@ -45,8 +46,8 @@ public class OrdinalGeneratorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOrdinals() {
|
public void testOrdinals_withIdentityFunction() {
|
||||||
OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>();
|
OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>(Function.identity());
|
||||||
int[] oneTwoOrds = ordinalGenerator.ordinals(Arrays.asList("One", "Two"));
|
int[] oneTwoOrds = ordinalGenerator.ordinals(Arrays.asList("One", "Two"));
|
||||||
int[] twoThreeOrds = ordinalGenerator.ordinals(Arrays.asList("Two", "Three"));
|
int[] twoThreeOrds = ordinalGenerator.ordinals(Arrays.asList("Two", "Three"));
|
||||||
assertEquals(oneTwoOrds[0], ordinalGenerator.ordinal("One"));
|
assertEquals(oneTwoOrds[0], ordinalGenerator.ordinal("One"));
|
||||||
@@ -54,4 +55,33 @@ public class OrdinalGeneratorTest {
|
|||||||
assertEquals(twoThreeOrds[0], ordinalGenerator.ordinal("Two"));
|
assertEquals(twoThreeOrds[0], ordinalGenerator.ordinal("Two"));
|
||||||
assertEquals(twoThreeOrds[1], ordinalGenerator.ordinal("Three"));
|
assertEquals(twoThreeOrds[1], ordinalGenerator.ordinal("Three"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOrdinal_withCanonicalizationFunction() {
|
||||||
|
OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>(String::toLowerCase);
|
||||||
|
|
||||||
|
int oneOrd = ordinalGenerator.ordinal("One");
|
||||||
|
int twoOrd = ordinalGenerator.ordinal("Two");
|
||||||
|
assertNotEquals(oneOrd, twoOrd);
|
||||||
|
|
||||||
|
assertEquals(oneOrd, ordinalGenerator.ordinal("ONE"));
|
||||||
|
assertEquals(twoOrd, ordinalGenerator.ordinal("two"));
|
||||||
|
|
||||||
|
int threeOrd = ordinalGenerator.ordinal("Three");
|
||||||
|
assertNotEquals(oneOrd, threeOrd);
|
||||||
|
assertNotEquals(twoOrd, threeOrd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOrdinals_withCanonicalizationFunction() {
|
||||||
|
OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>(String::toLowerCase);
|
||||||
|
|
||||||
|
int[] oneTwoOrds = ordinalGenerator.ordinals(Arrays.asList("One", "Two"));
|
||||||
|
int[] twoThreeOrds = ordinalGenerator.ordinals(Arrays.asList("Two", "Three"));
|
||||||
|
|
||||||
|
assertEquals(oneTwoOrds[0], ordinalGenerator.ordinal("ONE"));
|
||||||
|
assertEquals(oneTwoOrds[1], ordinalGenerator.ordinal("two"));
|
||||||
|
assertEquals(twoThreeOrds[0], ordinalGenerator.ordinal("TWO"));
|
||||||
|
assertEquals(twoThreeOrds[1], ordinalGenerator.ordinal("threE"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class TimeZoneCanonicalizerTest {
|
||||||
|
|
||||||
|
TimeZoneCanonicalizer mFunction = new TimeZoneCanonicalizer();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deprecatedTimeZonesAreEqualToCanonical() {
|
||||||
|
assertThat(mFunction.apply("America/Godthab")).isEqualTo("America/Nuuk");
|
||||||
|
assertThat(mFunction.apply("Australia/Currie")).isEqualTo("Australia/Hobart");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void wellKnownCanonicalIDs() {
|
||||||
|
assertThat(mFunction.apply("America/Detroit")).isEqualTo("America/Detroit");
|
||||||
|
assertThat(mFunction.apply("Europe/London")).isEqualTo("Europe/London");
|
||||||
|
assertThat(mFunction.apply("America/New_York")).isEqualTo("America/New_York");
|
||||||
|
assertThat(mFunction.apply("Europe/Volgograd")).isEqualTo("Europe/Volgograd");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void timeZonesAsGmtOffsetsTreatedAsCanonical() {
|
||||||
|
assertThat(mFunction.apply("Etc/GMT-11")).isEqualTo("Etc/GMT-11");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nonExistingOneMappedToThemselves() {
|
||||||
|
assertThat(mFunction.apply("Mars/Base")).isEqualTo("Mars/Base");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,6 +56,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* White-box unit tests for {@link TimeZoneDetectorStrategyImpl}.
|
* White-box unit tests for {@link TimeZoneDetectorStrategyImpl}.
|
||||||
@@ -1008,7 +1009,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
|||||||
// Check the various feature state values are what we expect.
|
// Check the various feature state values are what we expect.
|
||||||
assertFeatureStateMatchesConfig(expectedInternalConfig, actualState, expectedDetectionMode);
|
assertFeatureStateMatchesConfig(expectedInternalConfig, actualState, expectedDetectionMode);
|
||||||
|
|
||||||
OrdinalGenerator<String> tzIdOrdinalGenerator = new OrdinalGenerator<>();
|
OrdinalGenerator<String> tzIdOrdinalGenerator = new OrdinalGenerator<>(Function.identity());
|
||||||
MetricsTimeZoneDetectorState expectedState =
|
MetricsTimeZoneDetectorState expectedState =
|
||||||
MetricsTimeZoneDetectorState.create(
|
MetricsTimeZoneDetectorState.create(
|
||||||
tzIdOrdinalGenerator, expectedInternalConfig, expectedDeviceTimeZoneId,
|
tzIdOrdinalGenerator, expectedInternalConfig, expectedDeviceTimeZoneId,
|
||||||
|
|||||||
Reference in New Issue
Block a user