Add LTZP status APIs to the SDK
Give TimeZoneProviderService implementations the ability to supply
(optional) status information. This status information can be used for
two purposes:
1) To help report status to users in the SettingsUI (once plumbed
through).
2) To influence higher-level time zone detection behavior, i.e. so that
the time zone detection can understand that a TZP is unable to
perform its duties, perhaps something the platform cannot detect for
itself.
Test: atest core/tests/coretests/src/android/service/timezone/
Test: atest services/tests/servicestests/src/com/android/server/timezonedetector/location/
Bug: 236624675
Change-Id: Ifa66b8c968c0bdf31b6bdf55ead34b3fa1d9e6fa
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index fdb5e07..25e1402 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -11889,11 +11889,39 @@
method public abstract void onStopUpdates();
method public final void reportPermanentFailure(@NonNull Throwable);
method public final void reportSuggestion(@NonNull android.service.timezone.TimeZoneProviderSuggestion);
+ method public final void reportSuggestion(@NonNull android.service.timezone.TimeZoneProviderSuggestion, @NonNull android.service.timezone.TimeZoneProviderStatus);
method public final void reportUncertain();
+ method public final void reportUncertain(@NonNull android.service.timezone.TimeZoneProviderStatus);
field public static final String PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE = "android.service.timezone.PrimaryLocationTimeZoneProviderService";
field public static final String SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE = "android.service.timezone.SecondaryLocationTimeZoneProviderService";
}
+ public final class TimeZoneProviderStatus implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getConnectivityDependencyStatus();
+ method public int getLocationDetectionDependencyStatus();
+ method public int getTimeZoneResolutionOperationStatus();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.timezone.TimeZoneProviderStatus> CREATOR;
+ field public static final int DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT = 4; // 0x4
+ field public static final int DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS = 6; // 0x6
+ field public static final int DEPENDENCY_STATUS_DEGRADED_BY_SETTINGS = 5; // 0x5
+ field public static final int DEPENDENCY_STATUS_NOT_APPLICABLE = 1; // 0x1
+ field public static final int DEPENDENCY_STATUS_OK = 2; // 0x2
+ field public static final int DEPENDENCY_STATUS_TEMPORARILY_UNAVAILABLE = 3; // 0x3
+ field public static final int OPERATION_STATUS_FAILED = 3; // 0x3
+ field public static final int OPERATION_STATUS_NOT_APPLICABLE = 1; // 0x1
+ field public static final int OPERATION_STATUS_OK = 2; // 0x2
+ }
+
+ public static final class TimeZoneProviderStatus.Builder {
+ ctor public TimeZoneProviderStatus.Builder();
+ method @NonNull public android.service.timezone.TimeZoneProviderStatus build();
+ method @NonNull public android.service.timezone.TimeZoneProviderStatus.Builder setConnectivityDependencyStatus(int);
+ method @NonNull public android.service.timezone.TimeZoneProviderStatus.Builder setLocationDetectionDependencyStatus(int);
+ method @NonNull public android.service.timezone.TimeZoneProviderStatus.Builder setTimeZoneResolutionOperationStatus(int);
+ }
+
public final class TimeZoneProviderSuggestion implements android.os.Parcelable {
method public int describeContents();
method public long getElapsedRealtimeMillis();
diff --git a/core/java/android/service/timezone/TimeZoneProviderService.java b/core/java/android/service/timezone/TimeZoneProviderService.java
index 2cea95a..41ca94b 100644
--- a/core/java/android/service/timezone/TimeZoneProviderService.java
+++ b/core/java/android/service/timezone/TimeZoneProviderService.java
@@ -44,8 +44,8 @@
*
* <p>Once started, providers are expected to detect the time zone if possible, and report the
* result via {@link #reportSuggestion(TimeZoneProviderSuggestion)} or {@link
- * #reportUncertain()}. Providers may also report that they have permanently failed
- * by calling {@link #reportPermanentFailure(Throwable)}. See the javadocs for each
+ * #reportUncertain(TimeZoneProviderStatus)}. Providers may also report that they have permanently
+ * failed by calling {@link #reportPermanentFailure(Throwable)}. See the javadocs for each
* method for details.
*
* <p>After starting, providers are expected to issue their first callback within the timeout
@@ -213,8 +213,6 @@
*
* @param providerStatus provider status information that can influence detector service
* behavior and/or be reported via the device UI
- *
- * @hide
*/
public final void reportSuggestion(@NonNull TimeZoneProviderSuggestion suggestion,
@NonNull TimeZoneProviderStatus providerStatus) {
@@ -248,8 +246,9 @@
/**
* Indicates the time zone is not known because of an expected runtime state or error, e.g. when
- * the provider is unable to detect location, or there was a problem when resolving the location
- * to a time zone.
+ * the provider is unable to detect location, or there was connectivity issue.
+ *
+ * <p>See {@link #reportUncertain(TimeZoneProviderStatus)} for a more expressive version
*/
public final void reportUncertain() {
TimeZoneProviderStatus providerStatus = null;
@@ -264,8 +263,6 @@
*
* @param providerStatus provider status information that can influence detector service
* behavior and/or be reported via the device UI
- *
- * @hide
*/
public final void reportUncertain(@NonNull TimeZoneProviderStatus providerStatus) {
Objects.requireNonNull(providerStatus);
@@ -362,8 +359,8 @@
* <p>Between {@link #onStartUpdates(long)} and {@link #onStopUpdates()} calls, the Android
* system server holds the latest report from the provider in memory. After an initial report,
* provider implementations are only required to send a report via {@link
- * #reportSuggestion(TimeZoneProviderSuggestion)} or via {@link #reportUncertain()} when it
- * differs from the previous report.
+ * #reportSuggestion(TimeZoneProviderSuggestion, TimeZoneProviderStatus)} or via {@link
+ * #reportUncertain(TimeZoneProviderStatus)} when it differs from the previous report.
*
* <p>{@link #reportPermanentFailure(Throwable)} can also be called by provider implementations
* in rare cases, after which the provider should consider itself stopped and not make any
@@ -375,7 +372,8 @@
* Android system server may move on to use other providers or detection methods. Providers
* should therefore make best efforts during this time to generate a report, which could involve
* increased power usage. Providers should preferably report an explicit {@link
- * #reportUncertain()} if the time zone(s) cannot be detected within the initialization timeout.
+ * #reportUncertain(TimeZoneProviderStatus)} if the time zone(s) cannot be detected within the
+ * initialization timeout.
*
* @see #onStopUpdates() for the signal from the system server to stop sending reports
*/
diff --git a/core/java/android/service/timezone/TimeZoneProviderStatus.java b/core/java/android/service/timezone/TimeZoneProviderStatus.java
index 513068f..e0b78e9 100644
--- a/core/java/android/service/timezone/TimeZoneProviderStatus.java
+++ b/core/java/android/service/timezone/TimeZoneProviderStatus.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -65,6 +66,7 @@
*
* @hide
*/
+@SystemApi
public final class TimeZoneProviderStatus implements Parcelable {
/**
diff --git a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java b/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java
index 03e378f..9006cd9 100644
--- a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java
+++ b/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java
@@ -16,20 +16,15 @@
package android.service.timezone;
-import static android.app.time.ParcelableTestSupport.assertRoundTripParcelable;
-import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT;
import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS;
import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_OK;
-import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_FAILED;
import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_OK;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertThrows;
import org.junit.Test;
+/** Non-SDK tests. See CTS for SDK API tests. */
public class TimeZoneProviderStatusTest {
@Test
@@ -42,81 +37,4 @@
assertEquals(status, TimeZoneProviderStatus.parseProviderStatus(status.toString()));
}
-
- @Test
- public void testStatusValidation() {
- TimeZoneProviderStatus status = new TimeZoneProviderStatus.Builder()
- .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
- .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
- .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
- .build();
-
- assertThrows(IllegalArgumentException.class,
- () -> new TimeZoneProviderStatus.Builder(status)
- .setLocationDetectionDependencyStatus(-1)
- .build());
- assertThrows(IllegalArgumentException.class,
- () -> new TimeZoneProviderStatus.Builder(status)
- .setConnectivityDependencyStatus(-1)
- .build());
- assertThrows(IllegalArgumentException.class,
- () -> new TimeZoneProviderStatus.Builder(status)
- .setTimeZoneResolutionOperationStatus(-1)
- .build());
- }
-
- @Test
- public void testEqualsAndHashcode() {
- TimeZoneProviderStatus status1_1 = new TimeZoneProviderStatus.Builder()
- .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
- .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
- .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
- .build();
- assertEqualsAndHashcode(status1_1, status1_1);
- assertNotEquals(status1_1, null);
-
- {
- TimeZoneProviderStatus status1_2 =
- new TimeZoneProviderStatus.Builder(status1_1).build();
- assertEqualsAndHashcode(status1_1, status1_2);
- assertNotSame(status1_1, status1_2);
- }
-
- {
- TimeZoneProviderStatus status2 = new TimeZoneProviderStatus.Builder(status1_1)
- .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT)
- .build();
- assertNotEquals(status1_1, status2);
- }
-
- {
- TimeZoneProviderStatus status2 = new TimeZoneProviderStatus.Builder(status1_1)
- .setConnectivityDependencyStatus(DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT)
- .build();
- assertNotEquals(status1_1, status2);
- }
-
- {
- TimeZoneProviderStatus status2 = new TimeZoneProviderStatus.Builder(status1_1)
- .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_FAILED)
- .build();
- assertNotEquals(status1_1, status2);
- }
- }
-
- private static void assertEqualsAndHashcode(Object one, Object two) {
- assertEquals(one, two);
- assertEquals(two, one);
- assertEquals(one.hashCode(), two.hashCode());
- }
-
- @Test
- public void testParcelable() {
- TimeZoneProviderStatus status = new TimeZoneProviderStatus.Builder()
- .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
- .setConnectivityDependencyStatus(DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT)
- .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_FAILED)
- .build();
- assertRoundTripParcelable(status);
- }
}