From 2551c033df9631a46da9670f8ee9ab7d8fa425ec Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Thu, 16 Jan 2020 18:39:17 +0000 Subject: [PATCH] Add new module-lib APIs for MTS testing Several android.timezone classes have already been exposed for the telephony module work, so these tests provide coverage for those. Additional APIs have been exposed for MTS testing, i.e. to provide greater confidence that the tzdata module data is correct / is being read correctly. Also, small changes to existing code to make them consistent with new classes. Small docs improvements. Bug: 147884233 Test: see system/timezone change Change-Id: I047b29f17a41993f859947a6d6c3685896fe4cb6 --- api/module-lib-current.txt | 22 +++ .../android/timezone/CountryTimeZones.java | 1 + .../android/timezone/TelephonyLookup.java | 9 +- .../timezone/TelephonyNetworkFinder.java | 2 +- .../java/android/timezone/TimeZoneFinder.java | 29 +++- .../android/timezone/TzDataSetVersion.java | 154 ++++++++++++++++++ core/java/android/timezone/ZoneInfoDb.java | 66 ++++++++ core/java/android/util/TimeUtils.java | 2 +- 8 files changed, 269 insertions(+), 16 deletions(-) create mode 100644 core/java/android/timezone/TzDataSetVersion.java create mode 100644 core/java/android/timezone/ZoneInfoDb.java diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt index c8253a0b9e88a..c657e00496708 100644 --- a/api/module-lib-current.txt +++ b/api/module-lib-current.txt @@ -118,9 +118,31 @@ package android.timezone { } public final class TimeZoneFinder { + method @Nullable public String getIanaVersion(); method @NonNull public static android.timezone.TimeZoneFinder getInstance(); method @Nullable public android.timezone.CountryTimeZones lookupCountryTimeZones(@NonNull String); } + public final class TzDataSetVersion { + method public static int currentFormatMajorVersion(); + method public static int currentFormatMinorVersion(); + method public int getFormatMajorVersion(); + method public int getFormatMinorVersion(); + method public int getRevision(); + method @NonNull public String getRulesVersion(); + method public static boolean isCompatibleWithThisDevice(android.timezone.TzDataSetVersion); + method @NonNull public static android.timezone.TzDataSetVersion read() throws java.io.IOException, android.timezone.TzDataSetVersion.TzDataSetException; + } + + public static class TzDataSetVersion.TzDataSetException extends java.lang.Exception { + ctor public TzDataSetVersion.TzDataSetException(String); + ctor public TzDataSetVersion.TzDataSetException(String, Throwable); + } + + public final class ZoneInfoDb { + method @NonNull public static android.timezone.ZoneInfoDb getInstance(); + method @NonNull public String getVersion(); + } + } diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java index ada59d6d7d553..e5bbdf4b6eeaa 100644 --- a/core/java/android/timezone/CountryTimeZones.java +++ b/core/java/android/timezone/CountryTimeZones.java @@ -43,6 +43,7 @@ public final class CountryTimeZones { @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final class TimeZoneMapping { + @NonNull private libcore.timezone.CountryTimeZones.TimeZoneMapping mDelegate; TimeZoneMapping(libcore.timezone.CountryTimeZones.TimeZoneMapping delegate) { diff --git a/core/java/android/timezone/TelephonyLookup.java b/core/java/android/timezone/TelephonyLookup.java index 39dbe85cb485b..eebccf4aa577a 100644 --- a/core/java/android/timezone/TelephonyLookup.java +++ b/core/java/android/timezone/TelephonyLookup.java @@ -36,12 +36,8 @@ public class TelephonyLookup { @GuardedBy("sLock") private static TelephonyLookup sInstance; - @NonNull - private final libcore.timezone.TelephonyLookup mDelegate; - /** - * Obtains an instance for use when resolving telephony time zone information. This method never - * returns {@code null}. + * Obtains an instance for use when resolving telephony time zone information. */ @NonNull public static TelephonyLookup getInstance() { @@ -53,6 +49,9 @@ public class TelephonyLookup { } } + @NonNull + private final libcore.timezone.TelephonyLookup mDelegate; + private TelephonyLookup(@NonNull libcore.timezone.TelephonyLookup delegate) { mDelegate = Objects.requireNonNull(delegate); } diff --git a/core/java/android/timezone/TelephonyNetworkFinder.java b/core/java/android/timezone/TelephonyNetworkFinder.java index a81a516c4b33b..079d0882f1911 100644 --- a/core/java/android/timezone/TelephonyNetworkFinder.java +++ b/core/java/android/timezone/TelephonyNetworkFinder.java @@ -23,7 +23,7 @@ import android.annotation.SystemApi; import java.util.Objects; /** - * A class that can find telephony networks loaded via {@link TelephonyLookup}. + * A class that can find telephony network information loaded via {@link TelephonyLookup}. * * @hide */ diff --git a/core/java/android/timezone/TimeZoneFinder.java b/core/java/android/timezone/TimeZoneFinder.java index 15dfe62bb789b..9327b001a9c84 100644 --- a/core/java/android/timezone/TimeZoneFinder.java +++ b/core/java/android/timezone/TimeZoneFinder.java @@ -22,8 +22,10 @@ import android.annotation.SystemApi; import com.android.internal.annotations.GuardedBy; +import java.util.Objects; + /** - * A class that can be used to find time zones. + * A class that can be used to find time zones using information like country and offset. * * @hide */ @@ -34,15 +36,8 @@ public final class TimeZoneFinder { @GuardedBy("sLock") private static TimeZoneFinder sInstance; - private final libcore.timezone.TimeZoneFinder mDelegate; - - private TimeZoneFinder(libcore.timezone.TimeZoneFinder delegate) { - mDelegate = delegate; - } - /** - * Obtains an instance for use when resolving telephony time zone information. This method never - * returns {@code null}. + * Obtains the singleton instance. */ @NonNull public static TimeZoneFinder getInstance() { @@ -54,6 +49,22 @@ public final class TimeZoneFinder { return sInstance; } + @NonNull + private final libcore.timezone.TimeZoneFinder mDelegate; + + private TimeZoneFinder(@NonNull libcore.timezone.TimeZoneFinder delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns the IANA rules version associated with the data. If there is no version information + * or there is a problem reading the file then {@code null} is returned. + */ + @Nullable + public String getIanaVersion() { + return mDelegate.getIanaVersion(); + } + /** * Returns a {@link CountryTimeZones} object associated with the specified country code. * Caching is handled as needed. If the country code is not recognized or there is an error diff --git a/core/java/android/timezone/TzDataSetVersion.java b/core/java/android/timezone/TzDataSetVersion.java new file mode 100644 index 0000000000000..aba7c4c159035 --- /dev/null +++ b/core/java/android/timezone/TzDataSetVersion.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2020 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 android.timezone; + +import android.annotation.NonNull; +import android.annotation.SystemApi; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.IOException; +import java.util.Objects; + +/** + * Version information associated with the set of time zone data on a device. + * + *

Time Zone Data Sets have a major ({@link #getFormatMajorVersion()}) and minor + * ({@link #currentFormatMinorVersion()}) version number: + *

+ * + *

Data sets contain time zone rules and other data associated wtih a tzdb release + * ({@link #getRulesVersion()}) and an additional Android-specific revision number + * ({@link #getRevision()}). + * + *

See platform/system/timezone/README.android for more information. + * @hide + */ +@VisibleForTesting +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class TzDataSetVersion { + + /** + * Returns the major tz data format version supported by this device. + */ + public static int currentFormatMajorVersion() { + return libcore.timezone.TzDataSetVersion.currentFormatMajorVersion(); + } + + /** + * Returns the minor tz data format version supported by this device. + */ + public static int currentFormatMinorVersion() { + return libcore.timezone.TzDataSetVersion.currentFormatMinorVersion(); + } + + /** + * Returns true if the version information provided would be compatible with this device, i.e. + * with the current system image, and set of active modules. + */ + public static boolean isCompatibleWithThisDevice(TzDataSetVersion tzDataSetVersion) { + return libcore.timezone.TzDataSetVersion.isCompatibleWithThisDevice( + tzDataSetVersion.mDelegate); + } + + /** + * Reads the current Android time zone data set version file. + */ + @NonNull + public static TzDataSetVersion read() throws IOException, TzDataSetException { + try { + return new TzDataSetVersion( + libcore.timezone.TzDataSetVersion.readTimeZoneModuleVersion()); + } catch (libcore.timezone.TzDataSetVersion.TzDataSetException e) { + throw new TzDataSetException(e.getMessage(), e); + } + } + + /** + * A checked exception used in connection with time zone data sets. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static class TzDataSetException extends Exception { + + /** Creates an instance with a message. */ + public TzDataSetException(String message) { + super(message); + } + + /** Creates an instance with a message and a cause. */ + public TzDataSetException(String message, Throwable cause) { + super(message, cause); + } + } + + @NonNull + private final libcore.timezone.TzDataSetVersion mDelegate; + + private TzDataSetVersion(@NonNull libcore.timezone.TzDataSetVersion delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** Returns the major version number. See {@link TzDataSetVersion}. */ + public int getFormatMajorVersion() { + return mDelegate.formatMajorVersion; + } + + /** Returns the minor version number. See {@link TzDataSetVersion}. */ + public int getFormatMinorVersion() { + return mDelegate.formatMinorVersion; + } + + /** Returns the tzdb version string. See {@link TzDataSetVersion}. */ + @NonNull + public String getRulesVersion() { + return mDelegate.rulesVersion; + } + + /** Returns the Android revision. See {@link TzDataSetVersion}. */ + public int getRevision() { + return mDelegate.revision; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TzDataSetVersion that = (TzDataSetVersion) o; + return mDelegate.equals(that.mDelegate); + } + + @Override + public int hashCode() { + return Objects.hash(mDelegate); + } + + @Override + public String toString() { + return mDelegate.toString(); + } +} diff --git a/core/java/android/timezone/ZoneInfoDb.java b/core/java/android/timezone/ZoneInfoDb.java new file mode 100644 index 0000000000000..eb191e8e32722 --- /dev/null +++ b/core/java/android/timezone/ZoneInfoDb.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2020 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 android.timezone; + +import android.annotation.NonNull; +import android.annotation.SystemApi; + +import com.android.internal.annotations.GuardedBy; + +import java.util.Objects; + +/** + * Android's internal factory for java.util.TimeZone objects. Provides access to core library time + * zone metadata not available via {@link java.util.TimeZone}. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class ZoneInfoDb { + + private static Object sLock = new Object(); + @GuardedBy("sLock") + private static ZoneInfoDb sInstance; + + /** + * Obtains the singleton instance. + */ + @NonNull + public static ZoneInfoDb getInstance() { + synchronized (sLock) { + if (sInstance == null) { + sInstance = new ZoneInfoDb(libcore.timezone.ZoneInfoDB.getInstance()); + } + } + return sInstance; + } + + @NonNull + private final libcore.timezone.ZoneInfoDB mDelegate; + + private ZoneInfoDb(libcore.timezone.ZoneInfoDB delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns the tzdb version in use. + */ + @NonNull + public String getVersion() { + return mDelegate.getVersion(); + } +} diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index 8439f5aad0b10..dbd3f69e214e3 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -88,7 +88,7 @@ public class TimeUtils { * *

The list returned may be different from other on-device sources like * {@link android.icu.util.TimeZone#getRegion(String)} as it can be curated to avoid - * contentious mappings. + * contentious or obsolete mappings. * * @param countryCode the ISO 3166-1 alpha-2 code for the country as can be obtained using * {@link java.util.Locale#getCountry()}