Tidy up changes before API change

Extract non-API changes to make the API change commit smaller / more
focused. These changes are mostly naming, comment and some improved
validation. There's some toString() / parsing toString() changes and
associated tests for manual testing support used in later commits.

Test: atest services/tests/servicestests/src/com/android/server/timezonedetector/location/
Test: atest core/tests/coretests/src/android/service/timezone/
Bug: 236624675
Change-Id: I8f74e4bd0ad1a34b593afdf89b3e4840420a5d10
diff --git a/core/java/android/service/timezone/TimeZoneProviderEvent.java b/core/java/android/service/timezone/TimeZoneProviderEvent.java
index 714afee..e64bdd6 100644
--- a/core/java/android/service/timezone/TimeZoneProviderEvent.java
+++ b/core/java/android/service/timezone/TimeZoneProviderEvent.java
@@ -74,39 +74,53 @@
     @Nullable
     private final String mFailureCause;
 
-    // Populated when mType == EVENT_TYPE_SUGGESTION or EVENT_TYPE_UNCERTAIN
+    // May be populated when EVENT_TYPE_SUGGESTION or EVENT_TYPE_UNCERTAIN
     @Nullable
     private final TimeZoneProviderStatus mTimeZoneProviderStatus;
 
-    private TimeZoneProviderEvent(int type,
+    private TimeZoneProviderEvent(@EventType int type,
             @ElapsedRealtimeLong long creationElapsedMillis,
             @Nullable TimeZoneProviderSuggestion suggestion,
             @Nullable String failureCause,
             @Nullable TimeZoneProviderStatus timeZoneProviderStatus) {
-        mType = type;
+        mType = validateEventType(type);
         mCreationElapsedMillis = creationElapsedMillis;
         mSuggestion = suggestion;
         mFailureCause = failureCause;
         mTimeZoneProviderStatus = timeZoneProviderStatus;
+
+        // Confirm the type and the provider status agree.
+        if (mType == EVENT_TYPE_PERMANENT_FAILURE && mTimeZoneProviderStatus != null) {
+            throw new IllegalArgumentException(
+                    "Unexpected status: mType=" + mType
+                            + ", mTimeZoneProviderStatus=" + mTimeZoneProviderStatus);
+        }
+    }
+
+    private static @EventType int validateEventType(@EventType int eventType) {
+        if (eventType < EVENT_TYPE_PERMANENT_FAILURE || eventType > EVENT_TYPE_UNCERTAIN) {
+            throw new IllegalArgumentException(Integer.toString(eventType));
+        }
+        return eventType;
     }
 
     /** Returns an event of type {@link #EVENT_TYPE_SUGGESTION}. */
     public static TimeZoneProviderEvent createSuggestionEvent(
             @ElapsedRealtimeLong long creationElapsedMillis,
             @NonNull TimeZoneProviderSuggestion suggestion,
-            @NonNull TimeZoneProviderStatus providerStatus) {
+            @Nullable TimeZoneProviderStatus providerStatus) {
         return new TimeZoneProviderEvent(EVENT_TYPE_SUGGESTION, creationElapsedMillis,
-                Objects.requireNonNull(suggestion), null, Objects.requireNonNull(providerStatus));
+                Objects.requireNonNull(suggestion), null, providerStatus);
     }
 
     /** Returns an event of type {@link #EVENT_TYPE_UNCERTAIN}. */
     public static TimeZoneProviderEvent createUncertainEvent(
             @ElapsedRealtimeLong long creationElapsedMillis,
-            @NonNull TimeZoneProviderStatus timeZoneProviderStatus) {
+            @Nullable TimeZoneProviderStatus timeZoneProviderStatus) {
 
         return new TimeZoneProviderEvent(
                 EVENT_TYPE_UNCERTAIN, creationElapsedMillis, null, null,
-                Objects.requireNonNull(timeZoneProviderStatus));
+                timeZoneProviderStatus);
     }
 
     /** Returns an event of type {@link #EVENT_TYPE_PERMANENT_FAILURE}. */
@@ -148,8 +162,8 @@
     }
 
     /**
-     * Returns the status of the time zone provider. Populated when {@link #getType()} is {@link
-     * #EVENT_TYPE_UNCERTAIN} or {@link #EVENT_TYPE_SUGGESTION}.
+     * Returns the status of the time zone provider.  May be populated when {@link #getType()} is
+     * {@link #EVENT_TYPE_UNCERTAIN} or {@link #EVENT_TYPE_SUGGESTION}, otherwise {@code null}.
      */
     @Nullable
     public TimeZoneProviderStatus getTimeZoneProviderStatus() {
diff --git a/core/java/android/service/timezone/TimeZoneProviderService.java b/core/java/android/service/timezone/TimeZoneProviderService.java
index cd4a305..2cea95a 100644
--- a/core/java/android/service/timezone/TimeZoneProviderService.java
+++ b/core/java/android/service/timezone/TimeZoneProviderService.java
@@ -203,7 +203,8 @@
      * details.
      */
     public final void reportSuggestion(@NonNull TimeZoneProviderSuggestion suggestion) {
-        reportSuggestion(suggestion, TimeZoneProviderStatus.UNKNOWN);
+        TimeZoneProviderStatus providerStatus = null;
+        reportSuggestionInternal(suggestion, providerStatus);
     }
 
     /**
@@ -217,6 +218,12 @@
      */
     public final void reportSuggestion(@NonNull TimeZoneProviderSuggestion suggestion,
             @NonNull TimeZoneProviderStatus providerStatus) {
+        Objects.requireNonNull(providerStatus);
+        reportSuggestionInternal(suggestion, providerStatus);
+    }
+
+    private void reportSuggestionInternal(@NonNull TimeZoneProviderSuggestion suggestion,
+            @Nullable TimeZoneProviderStatus providerStatus) {
         Objects.requireNonNull(suggestion);
 
         mHandler.post(() -> {
@@ -245,7 +252,8 @@
      * to a time zone.
      */
     public final void reportUncertain() {
-        reportUncertain(TimeZoneProviderStatus.UNKNOWN);
+        TimeZoneProviderStatus providerStatus = null;
+        reportUncertainInternal(providerStatus);
     }
 
     /**
@@ -260,6 +268,11 @@
      * @hide
      */
     public final void reportUncertain(@NonNull TimeZoneProviderStatus providerStatus) {
+        Objects.requireNonNull(providerStatus);
+        reportUncertainInternal(providerStatus);
+    }
+
+    private void reportUncertainInternal(@Nullable TimeZoneProviderStatus providerStatus) {
         mHandler.post(() -> {
             synchronized (mLock) {
                 ITimeZoneProviderManager manager = mManager;
diff --git a/core/java/android/service/timezone/TimeZoneProviderStatus.java b/core/java/android/service/timezone/TimeZoneProviderStatus.java
index 87d7843..513068f 100644
--- a/core/java/android/service/timezone/TimeZoneProviderStatus.java
+++ b/core/java/android/service/timezone/TimeZoneProviderStatus.java
@@ -18,14 +18,18 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * Information about the status of a {@link TimeZoneProviderService}.
@@ -71,7 +75,7 @@
     @IntDef(prefix = "DEPENDENCY_STATUS_", value = {
             DEPENDENCY_STATUS_UNKNOWN,
             DEPENDENCY_STATUS_NOT_APPLICABLE,
-            DEPENDENCY_STATUS_WORKING,
+            DEPENDENCY_STATUS_OK,
             DEPENDENCY_STATUS_TEMPORARILY_UNAVAILABLE,
             DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT,
             DEPENDENCY_STATUS_DEGRADED_BY_SETTINGS,
@@ -81,14 +85,18 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface DependencyStatus {}
 
-    /** The dependency's status is unknown. */
+    /**
+     * The dependency's status is unknown.
+     *
+     * @hide
+     */
     public static final @DependencyStatus int DEPENDENCY_STATUS_UNKNOWN = 0;
 
     /** The dependency is not used by the provider's implementation. */
     public static final @DependencyStatus int DEPENDENCY_STATUS_NOT_APPLICABLE = 1;
 
-    /** The dependency is applicable and working well. */
-    public static final @DependencyStatus int DEPENDENCY_STATUS_WORKING = 2;
+    /** The dependency is applicable and there are no known problems. */
+    public static final @DependencyStatus int DEPENDENCY_STATUS_OK = 2;
 
     /**
      * The dependency is used but is temporarily unavailable, e.g. connectivity has been lost for an
@@ -136,76 +144,105 @@
     @IntDef(prefix = "OPERATION_STATUS_", value = {
             OPERATION_STATUS_UNKNOWN,
             OPERATION_STATUS_NOT_APPLICABLE,
-            OPERATION_STATUS_WORKING,
+            OPERATION_STATUS_OK,
             OPERATION_STATUS_FAILED,
     })
     @Target(ElementType.TYPE_USE)
     @Retention(RetentionPolicy.SOURCE)
     public @interface OperationStatus {}
 
-    /** The operation's status is unknown. */
+    /**
+     * The operation's status is unknown.
+     *
+     * @hide
+     */
     public static final @OperationStatus int OPERATION_STATUS_UNKNOWN = 0;
 
     /** The operation is not used by the provider's implementation. */
     public static final @OperationStatus int OPERATION_STATUS_NOT_APPLICABLE = 1;
 
-    /** The operation is applicable and working well. */
-    public static final @OperationStatus int OPERATION_STATUS_WORKING = 2;
+    /** The operation is applicable and there are no known problems. */
+    public static final @OperationStatus int OPERATION_STATUS_OK = 2;
 
-    /** The operation is applicable and failed. */
+    /** The operation is applicable and it recently failed. */
     public static final @OperationStatus int OPERATION_STATUS_FAILED = 3;
 
-    /**
-     * An instance that provides no information about status. Effectively a "null" status.
-     */
-    @NonNull
-    public static final TimeZoneProviderStatus UNKNOWN = new TimeZoneProviderStatus(
-            DEPENDENCY_STATUS_UNKNOWN, DEPENDENCY_STATUS_UNKNOWN, OPERATION_STATUS_UNKNOWN);
-
-    private final @DependencyStatus int mLocationDetectionStatus;
-    private final @DependencyStatus int mConnectivityStatus;
-    private final @OperationStatus int mTimeZoneResolutionStatus;
+    private final @DependencyStatus int mLocationDetectionDependencyStatus;
+    private final @DependencyStatus int mConnectivityDependencyStatus;
+    private final @OperationStatus int mTimeZoneResolutionOperationStatus;
 
     private TimeZoneProviderStatus(
             @DependencyStatus int locationDetectionStatus,
             @DependencyStatus int connectivityStatus,
             @OperationStatus int timeZoneResolutionStatus) {
-        mLocationDetectionStatus = requireValidDependencyStatus(locationDetectionStatus);
-        mConnectivityStatus = requireValidDependencyStatus(connectivityStatus);
-        mTimeZoneResolutionStatus = requireValidOperationStatus(timeZoneResolutionStatus);
+        mLocationDetectionDependencyStatus = locationDetectionStatus;
+        mConnectivityDependencyStatus = connectivityStatus;
+        mTimeZoneResolutionOperationStatus = timeZoneResolutionStatus;
     }
 
     /**
      * Returns the status of the location detection dependencies used by the provider (where
      * applicable).
      */
-    public @DependencyStatus int getLocationDetectionStatus() {
-        return mLocationDetectionStatus;
+    public @DependencyStatus int getLocationDetectionDependencyStatus() {
+        return mLocationDetectionDependencyStatus;
     }
 
     /**
      * Returns the status of the connectivity dependencies used by the provider (where applicable).
      */
-    public @DependencyStatus int getConnectivityStatus() {
-        return mConnectivityStatus;
+    public @DependencyStatus int getConnectivityDependencyStatus() {
+        return mConnectivityDependencyStatus;
     }
 
     /**
      * Returns the status of the time zone resolution operation used by the provider.
      */
-    public @OperationStatus int getTimeZoneResolutionStatus() {
-        return mTimeZoneResolutionStatus;
+    public @OperationStatus int getTimeZoneResolutionOperationStatus() {
+        return mTimeZoneResolutionOperationStatus;
     }
 
     @Override
     public String toString() {
         return "TimeZoneProviderStatus{"
-                + "mLocationDetectionStatus=" + mLocationDetectionStatus
-                + ", mConnectivityStatus=" + mConnectivityStatus
-                + ", mTimeZoneResolutionStatus=" + mTimeZoneResolutionStatus
+                + "mLocationDetectionDependencyStatus="
+                + dependencyStatusToString(mLocationDetectionDependencyStatus)
+                + ", mConnectivityDependencyStatus="
+                + dependencyStatusToString(mConnectivityDependencyStatus)
+                + ", mTimeZoneResolutionOperationStatus="
+                + operationStatusToString(mTimeZoneResolutionOperationStatus)
                 + '}';
     }
 
+    /**
+     * Parses a {@link TimeZoneProviderStatus} from a toString() string for manual command-line
+     * testing.
+     *
+     * @hide
+     */
+    @NonNull
+    public static TimeZoneProviderStatus parseProviderStatus(@NonNull String arg) {
+        // Note: "}" has to be escaped on Android with "\\}" because the regexp library is not based
+        // on OpenJDK code.
+        Pattern pattern = Pattern.compile("TimeZoneProviderStatus\\{"
+                + "mLocationDetectionDependencyStatus=([^,]+)"
+                + ", mConnectivityDependencyStatus=([^,]+)"
+                + ", mTimeZoneResolutionOperationStatus=([^\\}]+)"
+                + "\\}");
+        Matcher matcher = pattern.matcher(arg);
+        if (!matcher.matches()) {
+            throw new IllegalArgumentException("Unable to parse provider status: " + arg);
+        }
+        @DependencyStatus int locationDependencyStatus =
+                dependencyStatusFromString(matcher.group(1));
+        @DependencyStatus int connectivityDependencyStatus =
+                dependencyStatusFromString(matcher.group(2));
+        @OperationStatus int timeZoneResolutionOperationStatus =
+                operationStatusFromString(matcher.group(3));
+        return new TimeZoneProviderStatus(locationDependencyStatus, connectivityDependencyStatus,
+                timeZoneResolutionOperationStatus);
+    }
+
     public static final @NonNull Creator<TimeZoneProviderStatus> CREATOR = new Creator<>() {
         @Override
         public TimeZoneProviderStatus createFromParcel(Parcel in) {
@@ -229,9 +266,9 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel parcel, int flags) {
-        parcel.writeInt(mLocationDetectionStatus);
-        parcel.writeInt(mConnectivityStatus);
-        parcel.writeInt(mTimeZoneResolutionStatus);
+        parcel.writeInt(mLocationDetectionDependencyStatus);
+        parcel.writeInt(mConnectivityDependencyStatus);
+        parcel.writeInt(mTimeZoneResolutionOperationStatus);
     }
 
     @Override
@@ -243,23 +280,33 @@
             return false;
         }
         TimeZoneProviderStatus that = (TimeZoneProviderStatus) o;
-        return mLocationDetectionStatus == that.mLocationDetectionStatus
-                && mConnectivityStatus == that.mConnectivityStatus
-                && mTimeZoneResolutionStatus == that.mTimeZoneResolutionStatus;
+        return mLocationDetectionDependencyStatus == that.mLocationDetectionDependencyStatus
+                && mConnectivityDependencyStatus == that.mConnectivityDependencyStatus
+                && mTimeZoneResolutionOperationStatus == that.mTimeZoneResolutionOperationStatus;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(
-                mLocationDetectionStatus, mConnectivityStatus, mTimeZoneResolutionStatus);
+                mLocationDetectionDependencyStatus, mConnectivityDependencyStatus,
+                mTimeZoneResolutionOperationStatus);
+    }
+
+    /** @hide */
+    public boolean couldEnableTelephonyFallback() {
+        return mLocationDetectionDependencyStatus == DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT
+                || mLocationDetectionDependencyStatus == DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS
+                || mConnectivityDependencyStatus == DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT
+                || mConnectivityDependencyStatus == DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS;
     }
 
     /** A builder for {@link TimeZoneProviderStatus}. */
     public static final class Builder {
 
-        private @DependencyStatus int mLocationDetectionStatus = DEPENDENCY_STATUS_UNKNOWN;
-        private @DependencyStatus int mConnectivityStatus = DEPENDENCY_STATUS_UNKNOWN;
-        private @OperationStatus int mTimeZoneResolutionStatus = OPERATION_STATUS_UNKNOWN;
+        private @DependencyStatus int mLocationDetectionDependencyStatus =
+                DEPENDENCY_STATUS_UNKNOWN;
+        private @DependencyStatus int mConnectivityDependencyStatus = DEPENDENCY_STATUS_UNKNOWN;
+        private @OperationStatus int mTimeZoneResolutionOperationStatus = OPERATION_STATUS_UNKNOWN;
 
         /**
          * Creates a new builder instance. At creation time all status properties are set to
@@ -272,9 +319,9 @@
          * @hide
          */
         public Builder(TimeZoneProviderStatus toCopy) {
-            mLocationDetectionStatus = toCopy.mLocationDetectionStatus;
-            mConnectivityStatus = toCopy.mConnectivityStatus;
-            mTimeZoneResolutionStatus = toCopy.mTimeZoneResolutionStatus;
+            mLocationDetectionDependencyStatus = toCopy.mLocationDetectionDependencyStatus;
+            mConnectivityDependencyStatus = toCopy.mConnectivityDependencyStatus;
+            mTimeZoneResolutionOperationStatus = toCopy.mTimeZoneResolutionOperationStatus;
         }
 
         /**
@@ -282,8 +329,9 @@
          * See the {@code DEPENDENCY_STATUS_} constants for more information.
          */
         @NonNull
-        public Builder setLocationDetectionStatus(@DependencyStatus int locationDetectionStatus) {
-            mLocationDetectionStatus = locationDetectionStatus;
+        public Builder setLocationDetectionDependencyStatus(
+                @DependencyStatus int locationDetectionStatus) {
+            mLocationDetectionDependencyStatus = locationDetectionStatus;
             return this;
         }
 
@@ -292,8 +340,8 @@
          * See the {@code DEPENDENCY_STATUS_} constants for more information.
          */
         @NonNull
-        public Builder setConnectivityStatus(@DependencyStatus int connectivityStatus) {
-            mConnectivityStatus = connectivityStatus;
+        public Builder setConnectivityDependencyStatus(@DependencyStatus int connectivityStatus) {
+            mConnectivityDependencyStatus = connectivityStatus;
             return this;
         }
 
@@ -302,8 +350,9 @@
          * See the {@code OPERATION_STATUS_} constants for more information.
          */
         @NonNull
-        public Builder setTimeZoneResolutionStatus(@OperationStatus int timeZoneResolutionStatus) {
-            mTimeZoneResolutionStatus = timeZoneResolutionStatus;
+        public Builder setTimeZoneResolutionOperationStatus(
+                @OperationStatus int timeZoneResolutionStatus) {
+            mTimeZoneResolutionOperationStatus = timeZoneResolutionStatus;
             return this;
         }
 
@@ -313,11 +362,14 @@
         @NonNull
         public TimeZoneProviderStatus build() {
             return new TimeZoneProviderStatus(
-                    mLocationDetectionStatus, mConnectivityStatus, mTimeZoneResolutionStatus);
+                    requireValidDependencyStatus(mLocationDetectionDependencyStatus),
+                    requireValidDependencyStatus(mConnectivityDependencyStatus),
+                    requireValidOperationStatus(mTimeZoneResolutionOperationStatus));
         }
     }
 
-    private @OperationStatus int requireValidOperationStatus(@OperationStatus int operationStatus) {
+    private static @OperationStatus int requireValidOperationStatus(
+            @OperationStatus int operationStatus) {
         if (operationStatus < OPERATION_STATUS_UNKNOWN
                 || operationStatus > OPERATION_STATUS_FAILED) {
             throw new IllegalArgumentException(Integer.toString(operationStatus));
@@ -325,6 +377,45 @@
         return operationStatus;
     }
 
+    /** @hide */
+    @NonNull
+    public static String operationStatusToString(@OperationStatus int operationStatus) {
+        switch (operationStatus) {
+            case OPERATION_STATUS_UNKNOWN:
+                return "UNKNOWN";
+            case OPERATION_STATUS_NOT_APPLICABLE:
+                return "NOT_APPLICABLE";
+            case OPERATION_STATUS_OK:
+                return "OK";
+            case OPERATION_STATUS_FAILED:
+                return "FAILED";
+            default:
+                throw new IllegalArgumentException("Unknown status: " + operationStatus);
+        }
+    }
+
+    /** @hide */
+    public static @OperationStatus int operationStatusFromString(
+            @Nullable String operationStatusString) {
+
+        if (TextUtils.isEmpty(operationStatusString)) {
+            throw new IllegalArgumentException("Empty status: " + operationStatusString);
+        }
+
+        switch (operationStatusString) {
+            case "UNKNOWN":
+                return OPERATION_STATUS_UNKNOWN;
+            case "NOT_APPLICABLE":
+                return OPERATION_STATUS_NOT_APPLICABLE;
+            case "OK":
+                return OPERATION_STATUS_OK;
+            case "FAILED":
+                return OPERATION_STATUS_FAILED;
+            default:
+                throw new IllegalArgumentException("Unknown status: " + operationStatusString);
+        }
+    }
+
     private static @DependencyStatus int requireValidDependencyStatus(
             @DependencyStatus int dependencyStatus) {
         if (dependencyStatus < DEPENDENCY_STATUS_UNKNOWN
@@ -333,4 +424,56 @@
         }
         return dependencyStatus;
     }
+
+    /** @hide */
+    @NonNull
+    public static String dependencyStatusToString(@DependencyStatus int dependencyStatus) {
+        switch (dependencyStatus) {
+            case DEPENDENCY_STATUS_UNKNOWN:
+                return "UNKNOWN";
+            case DEPENDENCY_STATUS_NOT_APPLICABLE:
+                return "NOT_APPLICABLE";
+            case DEPENDENCY_STATUS_OK:
+                return "OK";
+            case DEPENDENCY_STATUS_TEMPORARILY_UNAVAILABLE:
+                return "TEMPORARILY_UNAVAILABLE";
+            case DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT:
+                return "BLOCKED_BY_ENVIRONMENT";
+            case DEPENDENCY_STATUS_DEGRADED_BY_SETTINGS:
+                return "DEGRADED_BY_SETTINGS";
+            case DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS:
+                return "BLOCKED_BY_SETTINGS";
+            default:
+                throw new IllegalArgumentException("Unknown status: " + dependencyStatus);
+        }
+    }
+
+    /** @hide */
+    public static @DependencyStatus int dependencyStatusFromString(
+            @Nullable String dependencyStatusString) {
+
+        if (TextUtils.isEmpty(dependencyStatusString)) {
+            throw new IllegalArgumentException("Empty status: " + dependencyStatusString);
+        }
+
+        switch (dependencyStatusString) {
+            case "UNKNOWN":
+                return DEPENDENCY_STATUS_UNKNOWN;
+            case "NOT_APPLICABLE":
+                return DEPENDENCY_STATUS_NOT_APPLICABLE;
+            case "OK":
+                return DEPENDENCY_STATUS_OK;
+            case "TEMPORARILY_UNAVAILABLE":
+                return DEPENDENCY_STATUS_TEMPORARILY_UNAVAILABLE;
+            case "BLOCKED_BY_ENVIRONMENT":
+                return DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT;
+            case "DEGRADED_BY_SETTINGS":
+                return DEPENDENCY_STATUS_DEGRADED_BY_SETTINGS;
+            case "BLOCKED_BY_SETTINGS":
+                return DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS;
+            default:
+                throw new IllegalArgumentException(
+                        "Unknown status: " + dependencyStatusString);
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderEventTest.java b/core/tests/coretests/src/android/service/timezone/TimeZoneProviderEventTest.java
index ab63f14..86ebdf3 100644
--- a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderEventTest.java
+++ b/core/tests/coretests/src/android/service/timezone/TimeZoneProviderEventTest.java
@@ -17,13 +17,18 @@
 package android.service.timezone;
 
 import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
-import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_WORKING;
+import static android.service.timezone.TimeZoneProviderEvent.EVENT_TYPE_PERMANENT_FAILURE;
+import static android.service.timezone.TimeZoneProviderEvent.EVENT_TYPE_SUGGESTION;
+import static android.service.timezone.TimeZoneProviderEvent.EVENT_TYPE_UNCERTAIN;
+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_WORKING;
+import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_OK;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -34,12 +39,92 @@
 
 public class TimeZoneProviderEventTest {
 
+    public static final TimeZoneProviderStatus ARBITRARY_TIME_ZONE_PROVIDER_STATUS =
+            new TimeZoneProviderStatus.Builder()
+                    .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
+                    .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
+                    .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
+                    .build();
+
+    @Test
+    public void createPermanentFailure() {
+        long creationElapsedMillis = 1111L;
+        String cause = "Cause";
+        TimeZoneProviderEvent event = TimeZoneProviderEvent.createPermanentFailureEvent(
+                creationElapsedMillis, cause);
+
+        assertEquals(EVENT_TYPE_PERMANENT_FAILURE, event.getType());
+        assertEquals(cause, event.getFailureCause());
+        assertEquals(creationElapsedMillis, event.getCreationElapsedMillis());
+        assertNull(event.getSuggestion());
+        assertNull(event.getTimeZoneProviderStatus());
+    }
+
+    @Test
+    public void createSuggestion() {
+        long creationElapsedMillis = 1111L;
+        TimeZoneProviderSuggestion suggestion = new TimeZoneProviderSuggestion.Builder()
+                .setElapsedRealtimeMillis(2222L)
+                .setTimeZoneIds(Collections.singletonList("Europe/London"))
+                .build();
+
+        TimeZoneProviderStatus reportedStatus = new TimeZoneProviderStatus.Builder()
+                .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
+                .build();
+
+        assertThrows(NullPointerException.class, () -> TimeZoneProviderEvent.createSuggestionEvent(
+                creationElapsedMillis, /*suggestion=*/null, reportedStatus));
+
+        // Only TimeZoneProvider can report itself certain.
+        {
+            TimeZoneProviderEvent event = TimeZoneProviderEvent.createSuggestionEvent(
+                    creationElapsedMillis, suggestion, reportedStatus);
+            assertEquals(EVENT_TYPE_SUGGESTION, event.getType());
+            assertEquals(creationElapsedMillis, event.getCreationElapsedMillis());
+            assertNull(event.getFailureCause());
+            assertEquals(suggestion, event.getSuggestion());
+        }
+
+        // Legacy API events can be created where the TimeZoneProviderStatus is omitted.
+        {
+            TimeZoneProviderStatus legacyStatus = null;
+            TimeZoneProviderEvent legacyEvent = TimeZoneProviderEvent.createSuggestionEvent(
+                    creationElapsedMillis, suggestion, legacyStatus);
+            assertEquals(legacyStatus, legacyEvent.getTimeZoneProviderStatus());
+        }
+    }
+
+    @Test
+    public void createUncertain() {
+        long creationElapsedMillis = 1111L;
+
+        // The TimeZoneProvider can report itself uncertain.
+        {
+            TimeZoneProviderEvent event = TimeZoneProviderEvent.createUncertainEvent(
+                    creationElapsedMillis, ARBITRARY_TIME_ZONE_PROVIDER_STATUS);
+            assertEquals(EVENT_TYPE_UNCERTAIN, event.getType());
+            assertEquals(creationElapsedMillis, event.getCreationElapsedMillis());
+            assertNull(event.getFailureCause());
+            assertNull(event.getSuggestion());
+        }
+
+        // Legacy API events can be created where the TimeZoneProviderStatus is omitted.
+        {
+            TimeZoneProviderStatus legacyStatus = null;
+            TimeZoneProviderEvent legacyEvent = TimeZoneProviderEvent.createUncertainEvent(
+                    creationElapsedMillis, legacyStatus);
+            assertEquals(legacyStatus, legacyEvent.getTimeZoneProviderStatus());
+        }
+    }
+
     @Test
     public void isEquivalentToAndEquals() {
         long creationElapsedMillis = 1111L;
         TimeZoneProviderEvent failEvent =
                 TimeZoneProviderEvent.createPermanentFailureEvent(creationElapsedMillis, "one");
-        TimeZoneProviderStatus providerStatus = TimeZoneProviderStatus.UNKNOWN;
+        TimeZoneProviderStatus providerStatus = ARBITRARY_TIME_ZONE_PROVIDER_STATUS;
 
         TimeZoneProviderEvent uncertainEvent =
                 TimeZoneProviderEvent.createUncertainEvent(creationElapsedMillis, providerStatus);
@@ -85,14 +170,14 @@
     @Test
     public void isEquivalentToAndEquals_uncertain() {
         TimeZoneProviderStatus status1 = new TimeZoneProviderStatus.Builder()
-                .setLocationDetectionStatus(DEPENDENCY_STATUS_WORKING)
-                .setConnectivityStatus(DEPENDENCY_STATUS_WORKING)
-                .setTimeZoneResolutionStatus(OPERATION_STATUS_WORKING)
+                .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
                 .build();
         TimeZoneProviderStatus status2 = new TimeZoneProviderStatus.Builder()
-                .setLocationDetectionStatus(DEPENDENCY_STATUS_WORKING)
-                .setConnectivityStatus(DEPENDENCY_STATUS_WORKING)
-                .setTimeZoneResolutionStatus(OPERATION_STATUS_FAILED)
+                .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_FAILED)
                 .build();
 
         TimeZoneProviderEvent uncertain1v1 =
@@ -123,14 +208,14 @@
     @Test
     public void isEquivalentToAndEquals_suggestion() {
         TimeZoneProviderStatus status1 = new TimeZoneProviderStatus.Builder()
-                .setLocationDetectionStatus(DEPENDENCY_STATUS_WORKING)
-                .setConnectivityStatus(DEPENDENCY_STATUS_WORKING)
-                .setTimeZoneResolutionStatus(OPERATION_STATUS_WORKING)
+                .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
                 .build();
         TimeZoneProviderStatus status2 = new TimeZoneProviderStatus.Builder()
-                .setLocationDetectionStatus(DEPENDENCY_STATUS_WORKING)
-                .setConnectivityStatus(DEPENDENCY_STATUS_WORKING)
-                .setTimeZoneResolutionStatus(OPERATION_STATUS_FAILED)
+                .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_FAILED)
                 .build();
         TimeZoneProviderSuggestion suggestion1 = new TimeZoneProviderSuggestion.Builder()
                 .setElapsedRealtimeMillis(1111L)
@@ -194,7 +279,13 @@
     @Test
     public void testParcelable_uncertain() {
         TimeZoneProviderEvent event = TimeZoneProviderEvent.createUncertainEvent(
-                1111L, TimeZoneProviderStatus.UNKNOWN);
+                1111L, ARBITRARY_TIME_ZONE_PROVIDER_STATUS);
+        assertRoundTripParcelable(event);
+    }
+
+    @Test
+    public void testParcelable_uncertain_legacy() {
+        TimeZoneProviderEvent event = TimeZoneProviderEvent.createUncertainEvent(1111L, null);
         assertRoundTripParcelable(event);
     }
 
@@ -204,7 +295,17 @@
                 .setTimeZoneIds(Arrays.asList("Europe/London", "Europe/Paris"))
                 .build();
         TimeZoneProviderEvent event = TimeZoneProviderEvent.createSuggestionEvent(
-                1111L, suggestion, TimeZoneProviderStatus.UNKNOWN);
+                1111L, suggestion, ARBITRARY_TIME_ZONE_PROVIDER_STATUS);
+        assertRoundTripParcelable(event);
+    }
+
+    @Test
+    public void testParcelable_suggestion_legacy() {
+        TimeZoneProviderSuggestion suggestion = new TimeZoneProviderSuggestion.Builder()
+                .setTimeZoneIds(Arrays.asList("Europe/London", "Europe/Paris"))
+                .build();
+        TimeZoneProviderEvent event = TimeZoneProviderEvent.createSuggestionEvent(
+                1111L, suggestion, null);
         assertRoundTripParcelable(event);
     }
 
diff --git a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java b/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java
index d61c33c..b7a595c 100644
--- a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java
+++ b/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java
@@ -18,9 +18,10 @@
 
 import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
 import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT;
-import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_WORKING;
+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_WORKING;
+import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_OK;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
@@ -32,33 +33,44 @@
 public class TimeZoneProviderStatusTest {
 
     @Test
+    public void parseProviderStatus() {
+        TimeZoneProviderStatus status = new TimeZoneProviderStatus.Builder()
+                .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS)
+                .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
+                .build();
+
+        assertEquals(status, TimeZoneProviderStatus.parseProviderStatus(status.toString()));
+    }
+
+    @Test
     public void testStatusValidation() {
         TimeZoneProviderStatus status = new TimeZoneProviderStatus.Builder()
-                .setLocationDetectionStatus(DEPENDENCY_STATUS_WORKING)
-                .setConnectivityStatus(DEPENDENCY_STATUS_WORKING)
-                .setTimeZoneResolutionStatus(DEPENDENCY_STATUS_WORKING)
+                .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
                 .build();
 
         assertThrows(IllegalArgumentException.class,
                 () -> new TimeZoneProviderStatus.Builder(status)
-                        .setLocationDetectionStatus(-1)
+                        .setLocationDetectionDependencyStatus(-1)
                         .build());
         assertThrows(IllegalArgumentException.class,
                 () -> new TimeZoneProviderStatus.Builder(status)
-                        .setConnectivityStatus(-1)
+                        .setConnectivityDependencyStatus(-1)
                         .build());
         assertThrows(IllegalArgumentException.class,
                 () -> new TimeZoneProviderStatus.Builder(status)
-                        .setTimeZoneResolutionStatus(-1)
+                        .setTimeZoneResolutionOperationStatus(-1)
                         .build());
     }
 
     @Test
     public void testEqualsAndHashcode() {
         TimeZoneProviderStatus status1_1 = new TimeZoneProviderStatus.Builder()
-                .setLocationDetectionStatus(DEPENDENCY_STATUS_WORKING)
-                .setConnectivityStatus(DEPENDENCY_STATUS_WORKING)
-                .setTimeZoneResolutionStatus(OPERATION_STATUS_WORKING)
+                .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
                 .build();
         assertEqualsAndHashcode(status1_1, status1_1);
         assertNotEquals(status1_1, null);
@@ -72,21 +84,21 @@
 
         {
             TimeZoneProviderStatus status2 = new TimeZoneProviderStatus.Builder(status1_1)
-                    .setLocationDetectionStatus(DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT)
+                    .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT)
                     .build();
             assertNotEquals(status1_1, status2);
         }
 
         {
             TimeZoneProviderStatus status2 = new TimeZoneProviderStatus.Builder(status1_1)
-                    .setConnectivityStatus(DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT)
+                    .setConnectivityDependencyStatus(DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT)
                     .build();
             assertNotEquals(status1_1, status2);
         }
 
         {
             TimeZoneProviderStatus status2 = new TimeZoneProviderStatus.Builder(status1_1)
-                    .setTimeZoneResolutionStatus(OPERATION_STATUS_FAILED)
+                    .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_FAILED)
                     .build();
             assertNotEquals(status1_1, status2);
         }
@@ -101,9 +113,9 @@
     @Test
     public void testParcelable() {
         TimeZoneProviderStatus status = new TimeZoneProviderStatus.Builder()
-                .setLocationDetectionStatus(DEPENDENCY_STATUS_WORKING)
-                .setConnectivityStatus(DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT)
-                .setTimeZoneResolutionStatus(OPERATION_STATUS_FAILED)
+                .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setConnectivityDependencyStatus(DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT)
+                .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_FAILED)
                 .build();
         assertRoundTripParcelable(status);
     }
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
index 90540b0..b1fc4f5 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
@@ -36,6 +36,7 @@
 import android.os.Handler;
 import android.os.SystemClock;
 import android.service.timezone.TimeZoneProviderEvent;
+import android.service.timezone.TimeZoneProviderStatus;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -294,6 +295,12 @@
                     || stateEnum == PROVIDER_STATE_DESTROYED;
         }
 
+        /** Returns the status reported by the provider, if available. */
+        @Nullable
+        TimeZoneProviderStatus getReportedStatus() {
+            return event == null ? null : event.getTimeZoneProviderStatus();
+        }
+
         @Override
         public String toString() {
             // this.provider is omitted deliberately to avoid recursion, since the provider holds
diff --git a/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessor.java b/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessor.java
index 8a6f927..aa2b74e 100644
--- a/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessor.java
+++ b/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessor.java
@@ -58,7 +58,7 @@
         if (hasInvalidZones(event)) {
             TimeZoneProviderStatus providerStatus = new TimeZoneProviderStatus.Builder(
                     event.getTimeZoneProviderStatus())
-                    .setTimeZoneResolutionStatus(OPERATION_STATUS_FAILED)
+                    .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_FAILED)
                     .build();
             return TimeZoneProviderEvent.createUncertainEvent(
                     event.getCreationElapsedMillis(), providerStatus);
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java
index 34d0082..f8d169b 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java
@@ -31,9 +31,9 @@
     @Override
     public TimeZoneProviderEvent preProcess(TimeZoneProviderEvent timeZoneProviderEvent) {
         if (mIsUncertain) {
+            TimeZoneProviderStatus timeZoneProviderStatus = null;
             return TimeZoneProviderEvent.createUncertainEvent(
-                    timeZoneProviderEvent.getCreationElapsedMillis(),
-                    TimeZoneProviderStatus.UNKNOWN);
+                    timeZoneProviderEvent.getCreationElapsedMillis(), timeZoneProviderStatus);
         }
         return timeZoneProviderEvent;
     }
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
index ed426cd..c18acd2 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
@@ -16,10 +16,10 @@
 package com.android.server.timezonedetector.location;
 
 import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_NOT_APPLICABLE;
+import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_OK;
 import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_TEMPORARILY_UNAVAILABLE;
-import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_WORKING;
+import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_OK;
 import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_UNKNOWN;
-import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_WORKING;
 
 import static com.android.server.timezonedetector.ConfigurationInternal.DETECTION_MODE_MANUAL;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
@@ -87,9 +87,9 @@
             createSuggestionEvent(asList("Europe/Paris"));
     private static final TimeZoneProviderStatus UNCERTAIN_PROVIDER_STATUS =
             new TimeZoneProviderStatus.Builder()
-                    .setLocationDetectionStatus(DEPENDENCY_STATUS_TEMPORARILY_UNAVAILABLE)
-                    .setConnectivityStatus(DEPENDENCY_STATUS_WORKING)
-                    .setTimeZoneResolutionStatus(OPERATION_STATUS_UNKNOWN)
+                    .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_TEMPORARILY_UNAVAILABLE)
+                    .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
+                    .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_UNKNOWN)
                     .build();
     private static final TimeZoneProviderEvent USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT =
             TimeZoneProviderEvent.createUncertainEvent(
@@ -1405,9 +1405,9 @@
 
     private static TimeZoneProviderEvent createSuggestionEvent(@NonNull List<String> timeZoneIds) {
         TimeZoneProviderStatus providerStatus = new TimeZoneProviderStatus.Builder()
-                .setLocationDetectionStatus(DEPENDENCY_STATUS_NOT_APPLICABLE)
-                .setConnectivityStatus(DEPENDENCY_STATUS_NOT_APPLICABLE)
-                .setTimeZoneResolutionStatus(OPERATION_STATUS_WORKING)
+                .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_NOT_APPLICABLE)
+                .setConnectivityDependencyStatus(DEPENDENCY_STATUS_NOT_APPLICABLE)
+                .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
                 .build();
         TimeZoneProviderSuggestion suggestion = new TimeZoneProviderSuggestion.Builder()
                 .setElapsedRealtimeMillis(ARBITRARY_TIME_MILLIS)
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
index 8429fa4..2bee7e6 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
@@ -15,6 +15,9 @@
  */
 package com.android.server.timezonedetector.location;
 
+import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_OK;
+import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_OK;
+
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
@@ -57,6 +60,12 @@
 public class LocationTimeZoneProviderTest {
 
     private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 123456789L;
+    private static final TimeZoneProviderStatus ARBITRARY_PROVIDER_STATUS =
+            new TimeZoneProviderStatus.Builder()
+                    .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
+                    .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
+                    .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
+                    .build();
 
     private TestThreadingDomain mTestThreadingDomain;
     private TestProviderListener mProviderListener;
@@ -80,91 +89,108 @@
                 mTimeZoneProviderEventPreProcessor);
 
         // initialize()
-        provider.initialize(mProviderListener);
-        provider.assertOnInitializeCalled();
+        {
+            provider.initialize(mProviderListener);
+            provider.assertOnInitializeCalled();
 
-        ProviderState currentState = assertAndReturnProviderState(
-                provider, providerMetricsLogger, PROVIDER_STATE_STOPPED);
-        assertNull(currentState.currentUserConfiguration);
-        assertSame(provider, currentState.provider);
-        mTestThreadingDomain.assertQueueEmpty();
+            ProviderState currentState = assertAndReturnProviderState(
+                    provider, providerMetricsLogger, PROVIDER_STATE_STOPPED,
+                    /*expectedReportedStatus=*/null);
+            assertNull(currentState.currentUserConfiguration);
+            assertSame(provider, currentState.provider);
+            mTestThreadingDomain.assertQueueEmpty();
+        }
+
+        ConfigurationInternal config = USER1_CONFIG_GEO_DETECTION_ENABLED;
 
         // startUpdates()
-        ConfigurationInternal config = USER1_CONFIG_GEO_DETECTION_ENABLED;
-        Duration arbitraryInitializationTimeout = Duration.ofMinutes(5);
-        Duration arbitraryInitializationTimeoutFuzz = Duration.ofMinutes(2);
-        Duration arbitraryEventFilteringAgeThreshold = Duration.ofMinutes(3);
-        provider.startUpdates(config, arbitraryInitializationTimeout,
-                arbitraryInitializationTimeoutFuzz, arbitraryEventFilteringAgeThreshold);
+        {
+            Duration arbitraryInitializationTimeout = Duration.ofMinutes(5);
+            Duration arbitraryInitializationTimeoutFuzz = Duration.ofMinutes(2);
+            Duration arbitraryEventFilteringAgeThreshold = Duration.ofMinutes(3);
+            provider.startUpdates(config, arbitraryInitializationTimeout,
+                    arbitraryInitializationTimeoutFuzz, arbitraryEventFilteringAgeThreshold);
 
-        provider.assertOnStartCalled(
-                arbitraryInitializationTimeout, arbitraryEventFilteringAgeThreshold);
+            provider.assertOnStartCalled(
+                    arbitraryInitializationTimeout, arbitraryEventFilteringAgeThreshold);
 
-        currentState = assertAndReturnProviderState(
-                provider, providerMetricsLogger, PROVIDER_STATE_STARTED_INITIALIZING);
-        assertSame(provider, currentState.provider);
-        assertEquals(config, currentState.currentUserConfiguration);
-        assertNull(currentState.event);
-        // The initialization timeout should be queued.
-        Duration expectedInitializationTimeout =
-                arbitraryInitializationTimeout.plus(arbitraryInitializationTimeoutFuzz);
-        mTestThreadingDomain.assertSingleDelayedQueueItem(expectedInitializationTimeout);
-        // We don't intend to trigger the timeout, so clear it.
-        mTestThreadingDomain.removeAllQueuedRunnables();
+            ProviderState currentState = assertAndReturnProviderState(
+                    provider, providerMetricsLogger, PROVIDER_STATE_STARTED_INITIALIZING,
+                    /*expectedReportedStatus=*/null);
+            assertSame(provider, currentState.provider);
+            assertEquals(config, currentState.currentUserConfiguration);
+            assertNull(currentState.event);
+            // The initialization timeout should be queued.
+            Duration expectedInitializationTimeout =
+                    arbitraryInitializationTimeout.plus(arbitraryInitializationTimeoutFuzz);
+            mTestThreadingDomain.assertSingleDelayedQueueItem(expectedInitializationTimeout);
+            // We don't intend to trigger the timeout, so clear it.
+            mTestThreadingDomain.removeAllQueuedRunnables();
 
-        // Entering started does not trigger an onProviderStateChanged() as it is requested by the
-        // controller.
-        mProviderListener.assertProviderChangeNotReported();
+            // Entering started does not trigger an onProviderStateChanged() as it is requested by
+            // the controller.
+            mProviderListener.assertProviderChangeNotReported();
+        }
 
         // Simulate a suggestion event being received.
-        TimeZoneProviderSuggestion suggestion = new TimeZoneProviderSuggestion.Builder()
-                .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS)
-                .setTimeZoneIds(Arrays.asList("Europe/London"))
-                .build();
-        TimeZoneProviderStatus providerStatus = TimeZoneProviderStatus.UNKNOWN;
-        TimeZoneProviderEvent event = TimeZoneProviderEvent.createSuggestionEvent(
-                ARBITRARY_ELAPSED_REALTIME_MILLIS, suggestion, providerStatus);
-        provider.simulateProviderEventReceived(event);
+        {
+            TimeZoneProviderSuggestion suggestion = new TimeZoneProviderSuggestion.Builder()
+                    .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS)
+                    .setTimeZoneIds(Arrays.asList("Europe/London"))
+                    .build();
+            TimeZoneProviderEvent event = TimeZoneProviderEvent.createSuggestionEvent(
+                    ARBITRARY_ELAPSED_REALTIME_MILLIS, suggestion, ARBITRARY_PROVIDER_STATUS);
+            provider.simulateProviderEventReceived(event);
 
-        currentState = assertAndReturnProviderState(
-                provider, providerMetricsLogger, PROVIDER_STATE_STARTED_CERTAIN);
-        assertSame(provider, currentState.provider);
-        assertEquals(event, currentState.event);
-        assertEquals(config, currentState.currentUserConfiguration);
-        mTestThreadingDomain.assertQueueEmpty();
-        mProviderListener.assertProviderChangeReported(PROVIDER_STATE_STARTED_CERTAIN);
+            ProviderState currentState = assertAndReturnProviderState(
+                    provider, providerMetricsLogger, PROVIDER_STATE_STARTED_CERTAIN,
+                    ARBITRARY_PROVIDER_STATUS);
+            assertSame(provider, currentState.provider);
+            assertEquals(event, currentState.event);
+            assertEquals(config, currentState.currentUserConfiguration);
+            mTestThreadingDomain.assertQueueEmpty();
+            mProviderListener.assertProviderChangeReported(PROVIDER_STATE_STARTED_CERTAIN);
+        }
 
         // Simulate an uncertain event being received.
-        event = TimeZoneProviderEvent.createUncertainEvent(ARBITRARY_ELAPSED_REALTIME_MILLIS,
-                TimeZoneProviderStatus.UNKNOWN);
-        provider.simulateProviderEventReceived(event);
+        {
+            TimeZoneProviderEvent event = TimeZoneProviderEvent.createUncertainEvent(
+                    ARBITRARY_ELAPSED_REALTIME_MILLIS, ARBITRARY_PROVIDER_STATUS);
+            provider.simulateProviderEventReceived(event);
 
-        currentState = assertAndReturnProviderState(
-                provider, providerMetricsLogger, PROVIDER_STATE_STARTED_UNCERTAIN);
-        assertSame(provider, currentState.provider);
-        assertEquals(event, currentState.event);
-        assertEquals(config, currentState.currentUserConfiguration);
-        mTestThreadingDomain.assertQueueEmpty();
-        mProviderListener.assertProviderChangeReported(PROVIDER_STATE_STARTED_UNCERTAIN);
+            ProviderState currentState = assertAndReturnProviderState(
+                    provider, providerMetricsLogger, PROVIDER_STATE_STARTED_UNCERTAIN,
+                    ARBITRARY_PROVIDER_STATUS);
+            assertSame(provider, currentState.provider);
+            assertEquals(event, currentState.event);
+            assertEquals(config, currentState.currentUserConfiguration);
+            mTestThreadingDomain.assertQueueEmpty();
+            mProviderListener.assertProviderChangeReported(PROVIDER_STATE_STARTED_UNCERTAIN);
+        }
 
         // stopUpdates()
-        provider.stopUpdates();
-        provider.assertOnStopUpdatesCalled();
+        {
+            provider.stopUpdates();
+            provider.assertOnStopUpdatesCalled();
 
-        currentState = assertAndReturnProviderState(
-                provider, providerMetricsLogger, PROVIDER_STATE_STOPPED);
-        assertSame(provider, currentState.provider);
-        assertEquals(PROVIDER_STATE_STOPPED, currentState.stateEnum);
-        assertNull(currentState.event);
-        assertNull(currentState.currentUserConfiguration);
-        mTestThreadingDomain.assertQueueEmpty();
-        // Entering stopped does not trigger an onProviderStateChanged() as it is requested by the
-        // controller.
-        mProviderListener.assertProviderChangeNotReported();
+            ProviderState currentState = assertAndReturnProviderState(
+                    provider, providerMetricsLogger, PROVIDER_STATE_STOPPED,
+                    /*expectedReportedStatus=*/null);
+            assertSame(provider, currentState.provider);
+            assertEquals(PROVIDER_STATE_STOPPED, currentState.stateEnum);
+            assertNull(currentState.event);
+            assertNull(currentState.currentUserConfiguration);
+            mTestThreadingDomain.assertQueueEmpty();
+            // Entering stopped does not trigger an onProviderStateChanged() as it is requested by
+            // the controller.
+            mProviderListener.assertProviderChangeNotReported();
+        }
 
         // destroy()
-        provider.destroy();
-        provider.assertOnDestroyCalled();
+        {
+            provider.destroy();
+            provider.assertOnDestroyCalled();
+        }
     }
 
     @Test
@@ -196,13 +222,12 @@
                 .setTimeZoneIds(Arrays.asList("Europe/London"))
                 .build();
         TimeZoneProviderEvent event = TimeZoneProviderEvent.createSuggestionEvent(
-                ARBITRARY_ELAPSED_REALTIME_MILLIS, suggestion, TimeZoneProviderStatus.UNKNOWN);
+                ARBITRARY_ELAPSED_REALTIME_MILLIS, suggestion, null);
         provider.simulateProviderEventReceived(event);
         provider.assertLatestRecordedState(PROVIDER_STATE_STARTED_CERTAIN);
 
         // Simulate an uncertain event being received.
-        event = TimeZoneProviderEvent.createUncertainEvent(ARBITRARY_ELAPSED_REALTIME_MILLIS,
-                TimeZoneProviderStatus.UNKNOWN);
+        event = TimeZoneProviderEvent.createUncertainEvent(ARBITRARY_ELAPSED_REALTIME_MILLIS, null);
         provider.simulateProviderEventReceived(event);
         provider.assertLatestRecordedState(PROVIDER_STATE_STARTED_UNCERTAIN);
 
@@ -239,7 +264,7 @@
                 .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS)
                 .setTimeZoneIds(invalidTimeZoneIds)
                 .build();
-        TimeZoneProviderStatus providerStatus = TimeZoneProviderStatus.UNKNOWN;
+        TimeZoneProviderStatus providerStatus = null;
         TimeZoneProviderEvent event = TimeZoneProviderEvent.createSuggestionEvent(
                 ARBITRARY_ELAPSED_REALTIME_MILLIS, invalidIdSuggestion, providerStatus);
         provider.simulateProviderEventReceived(event);
@@ -275,9 +300,11 @@
      */
     private static ProviderState assertAndReturnProviderState(
             TestLocationTimeZoneProvider provider,
-            RecordingProviderMetricsLogger providerMetricsLogger, int expectedStateEnum) {
+            RecordingProviderMetricsLogger providerMetricsLogger, int expectedStateEnum,
+            TimeZoneProviderStatus expectedReportedStatus) {
         ProviderState currentState = provider.getCurrentState();
         assertEquals(expectedStateEnum, currentState.stateEnum);
+        assertEquals(expectedReportedStatus, currentState.getReportedStatus());
         providerMetricsLogger.assertChangeLoggedAndRemove(expectedStateEnum);
         providerMetricsLogger.assertNoMoreLogEntries();
         return currentState;
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java
index c478604..f3440f7 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java
@@ -16,9 +16,9 @@
 
 package com.android.server.timezonedetector.location;
 
-import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_WORKING;
+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_WORKING;
+import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_OK;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
@@ -61,7 +61,7 @@
 
             TimeZoneProviderStatus expectedProviderStatus =
                     new TimeZoneProviderStatus.Builder(event.getTimeZoneProviderStatus())
-                            .setTimeZoneResolutionStatus(OPERATION_STATUS_FAILED)
+                            .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_FAILED)
                             .build();
 
             TimeZoneProviderEvent expectedResultEvent =
@@ -75,9 +75,9 @@
 
     private static TimeZoneProviderEvent timeZoneProviderEvent(String... timeZoneIds) {
         TimeZoneProviderStatus providerStatus = new TimeZoneProviderStatus.Builder()
-                .setLocationDetectionStatus(DEPENDENCY_STATUS_WORKING)
-                .setConnectivityStatus(DEPENDENCY_STATUS_WORKING)
-                .setTimeZoneResolutionStatus(OPERATION_STATUS_WORKING)
+                .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK)
+                .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK)
                 .build();
         TimeZoneProviderSuggestion suggestion = new TimeZoneProviderSuggestion.Builder()
                 .setTimeZoneIds(Arrays.asList(timeZoneIds))