Loading src/com/android/settings/datetime/timezone/model/FilteredCountryTimeZones.java +7 −1 Original line number Diff line number Diff line Loading @@ -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<String> mTimeZoneIds; public FilteredCountryTimeZones(CountryTimeZones countryTimeZones) { mCountryTimeZones = countryTimeZones; List<String> 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); Loading src/com/android/settings/datetime/timezone/model/TimeZoneData.java +13 −14 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 { Loading @@ -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; Loading @@ -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> countryTimeZones = mCountryZonesFinder .lookupCountryTimeZonesForZoneId(tzId); Set<String> 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) { Loading src/com/android/settings/datetime/timezone/model/TimeZoneDataLoader.java +1 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ public class TimeZoneDataLoader extends AsyncLoader<TimeZoneData> { @Override public TimeZoneData loadInBackground() { // Heavy operation due to reading the underlying file return new TimeZoneData(); return TimeZoneData.getInstance(); } @Override Loading tests/unit/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java 0 → 100644 +68 −0 Original line number Diff line number Diff line /* * 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<String> 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(); } } Loading
src/com/android/settings/datetime/timezone/model/FilteredCountryTimeZones.java +7 −1 Original line number Diff line number Diff line Loading @@ -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<String> mTimeZoneIds; public FilteredCountryTimeZones(CountryTimeZones countryTimeZones) { mCountryTimeZones = countryTimeZones; List<String> 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); Loading
src/com/android/settings/datetime/timezone/model/TimeZoneData.java +13 −14 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 { Loading @@ -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; Loading @@ -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> countryTimeZones = mCountryZonesFinder .lookupCountryTimeZonesForZoneId(tzId); Set<String> 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) { Loading
src/com/android/settings/datetime/timezone/model/TimeZoneDataLoader.java +1 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ public class TimeZoneDataLoader extends AsyncLoader<TimeZoneData> { @Override public TimeZoneData loadInBackground() { // Heavy operation due to reading the underlying file return new TimeZoneData(); return TimeZoneData.getInstance(); } @Override Loading
tests/unit/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java 0 → 100644 +68 −0 Original line number Diff line number Diff line /* * 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<String> 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(); } }