diff --git a/src/com/android/settings/datetime/timezone/model/FilteredCountryTimeZones.java b/src/com/android/settings/datetime/timezone/model/FilteredCountryTimeZones.java index d1b6ed97142..858c8eb1b39 100644 --- a/src/com/android/settings/datetime/timezone/model/FilteredCountryTimeZones.java +++ b/src/com/android/settings/datetime/timezone/model/FilteredCountryTimeZones.java @@ -27,13 +27,19 @@ import java.util.stream.Collectors; */ public class FilteredCountryTimeZones { + // New timezone list and the meta data of time zone, notUsedAfter, is introduced in Android P + // in 2018. Only show time zone used in or after 2018. + private static final long MIN_USE_DATE_OF_TIMEZONE = 1514764800000L; // 1/1/2018 00:00 UTC + private final CountryTimeZones mCountryTimeZones; private final List mTimeZoneIds; public FilteredCountryTimeZones(CountryTimeZones countryTimeZones) { mCountryTimeZones = countryTimeZones; List timeZoneIds = countryTimeZones.getTimeZoneMappings().stream() - .filter(timeZoneMapping -> timeZoneMapping.showInPicker) + .filter(timeZoneMapping -> + timeZoneMapping.showInPicker && (timeZoneMapping.notUsedAfter == null + || timeZoneMapping.notUsedAfter >= MIN_USE_DATE_OF_TIMEZONE)) .map(timeZoneMapping -> timeZoneMapping.timeZoneId) .collect(Collectors.toList()); mTimeZoneIds = Collections.unmodifiableList(timeZoneIds); diff --git a/src/com/android/settings/datetime/timezone/model/TimeZoneData.java b/src/com/android/settings/datetime/timezone/model/TimeZoneData.java index b78534d6671..14fc9a1477d 100644 --- a/src/com/android/settings/datetime/timezone/model/TimeZoneData.java +++ b/src/com/android/settings/datetime/timezone/model/TimeZoneData.java @@ -16,6 +16,7 @@ package com.android.settings.datetime.timezone.model; import android.support.annotation.VisibleForTesting; +import android.support.v4.util.ArraySet; import libcore.util.CountryTimeZones; import libcore.util.CountryZonesFinder; @@ -27,12 +28,11 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; -import java.util.stream.Collectors; /** * Wrapper of CountryZonesFinder to normalize the country code and only show the regions that are * has time zone shown in the time zone picker. - * The constructor reads the data from underlying file, and this means it should not be called + * getInstance() reads the data from underlying file, and this means it should not be called * from the UI thread. */ public class TimeZoneData { @@ -47,15 +47,11 @@ public class TimeZoneData { if (data != null) { return data; } - data = new TimeZoneData(); + data = new TimeZoneData(TimeZoneFinder.getInstance().getCountryZonesFinder()); sCache = new WeakReference<>(data); return data; } - public TimeZoneData() { - this(TimeZoneFinder.getInstance().getCountryZonesFinder()); - } - @VisibleForTesting public TimeZoneData(CountryZonesFinder countryZonesFinder) { mCountryZonesFinder = countryZonesFinder; @@ -70,13 +66,16 @@ public class TimeZoneData { if (tzId == null) { return Collections.emptySet(); } - return mCountryZonesFinder.lookupCountryTimeZonesForZoneId(tzId).stream() - .filter(countryTimeZones -> - countryTimeZones.getTimeZoneMappings().stream() - .anyMatch(mapping -> - mapping.timeZoneId.equals(tzId) && mapping.showInPicker)) - .map(countryTimeZones -> normalizeRegionId(countryTimeZones.getCountryIso())) - .collect(Collectors.toSet()); + List countryTimeZones = mCountryZonesFinder + .lookupCountryTimeZonesForZoneId(tzId); + Set regionIds = new ArraySet<>(); + for (CountryTimeZones countryTimeZone : countryTimeZones) { + FilteredCountryTimeZones filteredZones = new FilteredCountryTimeZones(countryTimeZone); + if (filteredZones.getTimeZoneIds().contains(tzId)) { + regionIds.add(filteredZones.getRegionId()); + } + } + return regionIds; } public FilteredCountryTimeZones lookupCountryTimeZones(String regionId) { diff --git a/src/com/android/settings/datetime/timezone/model/TimeZoneDataLoader.java b/src/com/android/settings/datetime/timezone/model/TimeZoneDataLoader.java index 89908d87f7b..92232072814 100644 --- a/src/com/android/settings/datetime/timezone/model/TimeZoneDataLoader.java +++ b/src/com/android/settings/datetime/timezone/model/TimeZoneDataLoader.java @@ -32,7 +32,7 @@ public class TimeZoneDataLoader extends AsyncLoader { @Override public TimeZoneData loadInBackground() { // Heavy operation due to reading the underlying file - return new TimeZoneData(); + return TimeZoneData.getInstance(); } @Override diff --git a/tests/unit/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java b/tests/unit/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java new file mode 100644 index 00000000000..0b5ade8fc11 --- /dev/null +++ b/tests/unit/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2018 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.settings.datetime.timezone.model; + +import static com.google.common.truth.Truth.assertThat; + +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Set; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class TimeZoneDataTest { + + private TimeZoneData mTimeZoneData; + @Before + public void setUp() { + mTimeZoneData = TimeZoneData.getInstance(); + } + + @Test + public void lookupCountryTimeZones_shouldReturnAtLeastOneTimeZoneInEveryRegion() { + Set regionIds = mTimeZoneData.getRegionIds(); + for (String regionId : regionIds) { + FilteredCountryTimeZones countryTimeZones = + mTimeZoneData.lookupCountryTimeZones(regionId); + assertThat(countryTimeZones).isNotNull(); + assertThat(countryTimeZones.getTimeZoneIds().size()).isGreaterThan(0); + } + } + + @Test + public void lookupCountryCodesForZoneId_shouldNotReturnHiddenZone() { + /* + Simferopol is filtered out for two reasons: + 1) because we specifically exclude it with the picker attribute, and + 2) because it's the same as Moscow after Oct 2014. + */ + assertThat(mTimeZoneData.lookupCountryCodesForZoneId("Europe/Simferopol").isEmpty()) + .isTrue(); + // Metlakatla has the same time as Anchorage after 2015 + assertThat(mTimeZoneData.lookupCountryCodesForZoneId("America/Metlakatla").isEmpty()) + .isTrue(); + assertThat(mTimeZoneData.lookupCountryCodesForZoneId("Europe/London").isEmpty()) + .isFalse(); + assertThat(mTimeZoneData.lookupCountryCodesForZoneId("America/Los_Angeles").isEmpty()) + .isFalse(); + } +}