Merge "Merge Android10 QPR1 into AOSP master"
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index e151c7c..822d249 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -45,8 +45,8 @@
 import android.provider.Telephony;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.AccessNetworkConstants.TransportType;
-import android.telephony.Annotation.DataFailureCause;
 import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.DataFailureCause;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DataFailCause;
 import android.telephony.NetworkRegistrationInfo;
@@ -88,6 +88,8 @@
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 
+import libcore.net.InetAddressUtils;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -1367,7 +1369,11 @@
     public static boolean isIpAddress(String address) {
         if (address == null) return false;
 
-        return InetAddress.isNumeric(address);
+        // Accept IPv6 addresses (only) in square brackets for compatibility.
+        if (address.startsWith("[") && address.endsWith("]") && address.indexOf(':') != -1) {
+            address = address.substring(1, address.length() - 1);
+        }
+        return InetAddressUtils.isNumericAddress(address);
     }
 
     private SetupResult setLinkProperties(DataCallResponse response,
@@ -1441,7 +1447,8 @@
                 for (InetAddress gateway : response.getGatewayAddresses()) {
                     // Allow 0.0.0.0 or :: as a gateway;
                     // this indicates a point-to-point interface.
-                    linkProperties.addRoute(new RouteInfo(gateway));
+                    linkProperties.addRoute(new RouteInfo(null, gateway, null,
+                            RouteInfo.RTN_UNICAST));
                 }
 
                 // set interface MTU
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index c30b6eb..b4500c6 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -68,7 +68,6 @@
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.Annotation.ApnType;
 import android.telephony.Annotation.DataFailureCause;
-import android.telephony.Annotation.NetworkType;
 import android.telephony.Annotation.RilRadioTechnology;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellLocation;
@@ -465,14 +464,6 @@
         }
 
         /**
-         * Get Tcp Tx/Rx packet count from TrafficStats
-         */
-        public void updateTcpTxRxSum() {
-            this.txPkts = TrafficStats.getMobileTcpTxPackets();
-            this.rxPkts = TrafficStats.getMobileTcpRxPackets();
-        }
-
-        /**
          * Get total Tx/Rx packet count from TrafficStats
          */
         public void updateTotalTxRxSum() {
@@ -625,11 +616,6 @@
 
     //***** Constants
 
-    // Used by puppetmaster/*/radio_stress.py
-    private static final String PUPPET_MASTER_RADIO_STRESS_TEST = "gsm.defaultpdpcontext.active";
-
-    private static final int POLL_PDP_MILLIS = 5 * 1000;
-
     private static final int PROVISIONING_SPINNER_TIMEOUT_MILLIS = 120 * 1000;
 
     static final Uri PREFERAPN_NO_UPDATE_URI_USING_SUBID =
@@ -1732,10 +1718,6 @@
      */
     @VisibleForTesting
     public @NonNull ArrayList<ApnSetting> fetchDunApns() {
-        if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)) {
-            log("fetchDunApns: net.tethering.noprovisioning=true ret: empty list");
-            return new ArrayList<ApnSetting>(0);
-        }
         int bearer = getDataRat();
         ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>();
         ArrayList<ApnSetting> retDunSettings = new ArrayList<ApnSetting>();
@@ -2707,24 +2689,12 @@
                 }
 
                 // everything is setup
-                if (TextUtils.equals(apnContext.getApnType(), PhoneConstants.APN_TYPE_DEFAULT)) {
-                    try {
-                        SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "true");
-                    } catch (RuntimeException ex) {
-                        log("Failed to set PUPPET_MASTER_RADIO_STRESS_TEST to true");
-                    }
-                    if (mCanSetPreferApn && mPreferredApn == null) {
-                        if (DBG) log("onDataSetupComplete: PREFERRED APN is null");
-                        mPreferredApn = apn;
-                        if (mPreferredApn != null) {
-                            setPreferredApn(mPreferredApn.getId());
-                        }
-                    }
-                } else {
-                    try {
-                        SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
-                    } catch (RuntimeException ex) {
-                        log("Failed to set PUPPET_MASTER_RADIO_STRESS_TEST to false");
+                if (TextUtils.equals(apnContext.getApnType(), PhoneConstants.APN_TYPE_DEFAULT)
+                        && mCanSetPreferApn && mPreferredApn == null) {
+                    if (DBG) log("onDataSetupComplete: PREFERRED APN is null");
+                    mPreferredApn = apn;
+                    if (mPreferredApn != null) {
+                        setPreferredApn(mPreferredApn.getId());
                     }
                 }
 
@@ -2734,7 +2704,8 @@
                 checkDataRoamingStatus(false);
 
                 boolean isProvApn = apnContext.isProvisioningApn();
-                final ConnectivityManager cm = ConnectivityManager.from(mPhone.getContext());
+                final ConnectivityManager cm = (ConnectivityManager) mPhone.getContext()
+                        .getSystemService(Context.CONNECTIVITY_SERVICE);
                 if (mProvisionBroadcastReceiver != null) {
                     mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver);
                     mProvisionBroadcastReceiver = null;
@@ -2935,11 +2906,6 @@
         }
         // If APN is still enabled, try to bring it back up automatically
         if (mAttached.get() && apnContext.isReady() && retryAfterDisconnected(apnContext)) {
-            try {
-                SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
-            } catch (RuntimeException ex) {
-                log("Failed to set PUPPET_MASTER_RADIO_STRESS_TEST to false");
-            }
             // Wait a bit before trying the next APN, so that
             // we're not tying up the RIL command channel.
             // This also helps in any external dependency to turn off the context.
@@ -4527,7 +4493,7 @@
         long sent, received;
 
         TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum);
-        mDataStallTxRxSum.updateTcpTxRxSum();
+        mDataStallTxRxSum.updateTotalTxRxSum();
 
         if (VDBG_STALL) {
             log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum +
diff --git a/src/java/com/android/internal/telephony/nitz/NewNitzStateMachineImpl.java b/src/java/com/android/internal/telephony/nitz/NewNitzStateMachineImpl.java
index 6db5b4f..27d23e3 100644
--- a/src/java/com/android/internal/telephony/nitz/NewNitzStateMachineImpl.java
+++ b/src/java/com/android/internal/telephony/nitz/NewNitzStateMachineImpl.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
 import android.content.Context;
 import android.telephony.Rlog;
 import android.util.TimestampedValue;
@@ -28,7 +29,6 @@
 import com.android.internal.telephony.NitzStateMachine;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.TimeZoneLookupHelper;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
@@ -287,6 +287,7 @@
             PhoneTimeZoneSuggestion suggestion =
                     mTimeZoneSuggester.getTimeZoneSuggestion(mPhoneId, countryIsoCode, nitzSignal);
             suggestion.addDebugInfo("Detection reason=" + reason);
+
             if (DBG) {
                 Rlog.d(LOG_TAG, "doTimeZoneDetection: countryIsoCode=" + countryIsoCode
                         + ", nitzSignal=" + nitzSignal + ", suggestion=" + suggestion
diff --git a/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelper.java b/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelper.java
index 7984c97..bc3a726 100644
--- a/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelper.java
+++ b/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelper.java
@@ -19,8 +19,8 @@
 import android.annotation.NonNull;
 import android.app.timedetector.PhoneTimeSuggestion;
 import android.app.timedetector.TimeDetector;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
 
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.PrintWriter;
diff --git a/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelperImpl.java b/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelperImpl.java
index 5689660..36d38f6 100644
--- a/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelperImpl.java
+++ b/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelperImpl.java
@@ -20,14 +20,14 @@
 import android.annotation.Nullable;
 import android.app.timedetector.PhoneTimeSuggestion;
 import android.app.timedetector.TimeDetector;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+import android.app.timezonedetector.TimeZoneDetector;
 import android.content.Context;
 import android.util.LocalLog;
 import android.util.TimestampedValue;
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
-import com.android.internal.telephony.nitz.service.TimeZoneDetectionService;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.PrintWriter;
@@ -40,7 +40,7 @@
 
     private final int mPhoneId;
     private final TimeDetector mTimeDetector;
-    private final TimeZoneDetectionService mTimeZoneDetector;
+    private final TimeZoneDetector mTimeZoneDetector;
 
     private final LocalLog mTimeZoneLog = new LocalLog(30);
     private final LocalLog mTimeLog = new LocalLog(30);
@@ -57,7 +57,8 @@
         mPhoneId = phone.getPhoneId();
         Context context = Objects.requireNonNull(phone.getContext());
         mTimeDetector = Objects.requireNonNull(context.getSystemService(TimeDetector.class));
-        mTimeZoneDetector = Objects.requireNonNull(TimeZoneDetectionService.getInstance(context));
+        mTimeZoneDetector =
+                Objects.requireNonNull(context.getSystemService(TimeZoneDetector.class));
     }
 
     @Override
@@ -110,14 +111,10 @@
         mTimeZoneLog.dump(ipw);
         ipw.decreaseIndent();
         ipw.decreaseIndent();
-
-        // TODO Remove this line when the service moves to the system server.
-        mTimeZoneDetector.dumpLogs(ipw);
     }
 
     @Override
     public void dumpState(PrintWriter pw) {
         pw.println(" NewTimeServiceHelperImpl.mLastSuggestedTimeZone=" + mLastSuggestedTimeZone);
-        mTimeZoneDetector.dumpState(pw);
     }
 }
diff --git a/src/java/com/android/internal/telephony/nitz/TimeZoneSuggesterImpl.java b/src/java/com/android/internal/telephony/nitz/TimeZoneSuggesterImpl.java
index c5d9df6..8d8bab9 100644
--- a/src/java/com/android/internal/telephony/nitz/TimeZoneSuggesterImpl.java
+++ b/src/java/com/android/internal/telephony/nitz/TimeZoneSuggesterImpl.java
@@ -16,14 +16,11 @@
 
 package com.android.internal.telephony.nitz;
 
-import static com.android.internal.telephony.TimeZoneLookupHelper.CountryResult.QUALITY_DEFAULT_BOOSTED;
-import static com.android.internal.telephony.TimeZoneLookupHelper.CountryResult.QUALITY_MULTIPLE_ZONES_DIFFERENT_OFFSETS;
-import static com.android.internal.telephony.TimeZoneLookupHelper.CountryResult.QUALITY_MULTIPLE_ZONES_SAME_OFFSET;
-import static com.android.internal.telephony.TimeZoneLookupHelper.CountryResult.QUALITY_SINGLE_ZONE;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.createEmptySuggestion;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.createEmptySuggestion;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
 import android.telephony.Rlog;
 import android.text.TextUtils;
 import android.util.TimestampedValue;
@@ -34,7 +31,6 @@
 import com.android.internal.telephony.TimeZoneLookupHelper;
 import com.android.internal.telephony.TimeZoneLookupHelper.CountryResult;
 import com.android.internal.telephony.nitz.NewNitzStateMachineImpl.TimeZoneSuggester;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
 
 import java.util.Objects;
 
@@ -66,11 +62,13 @@
             if (nitzSignal != null) {
                 NitzData nitzData = nitzSignal.getValue();
                 if (nitzData.getEmulatorHostTimeZone() != null) {
-                    overridingSuggestion = new PhoneTimeZoneSuggestion(phoneId);
-                    overridingSuggestion.setZoneId(nitzData.getEmulatorHostTimeZone().getID());
-                    overridingSuggestion.setMatchType(PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID);
-                    overridingSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-                    overridingSuggestion.addDebugInfo("Emulator time zone override: " + nitzData);
+                    PhoneTimeZoneSuggestion.Builder builder =
+                            new PhoneTimeZoneSuggestion.Builder(phoneId)
+                            .setZoneId(nitzData.getEmulatorHostTimeZone().getID())
+                            .setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID)
+                            .setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE)
+                            .addDebugInfo("Emulator time zone override: " + nitzData);
+                    overridingSuggestion = builder.build();
                 }
             }
 
@@ -125,7 +123,6 @@
                     + ", nitzSignal=" + nitzSignal
                     + ", e=" + e.getMessage();
             PhoneTimeZoneSuggestion errorSuggestion = createEmptySuggestion(phoneId, message);
-            errorSuggestion.addDebugInfo(message);
             Rlog.w(LOG_TAG, message, e);
             return errorSuggestion;
         }
@@ -142,21 +139,25 @@
         Objects.requireNonNull(nitzSignal);
         NitzData nitzData = Objects.requireNonNull(nitzSignal.getValue());
 
-        PhoneTimeZoneSuggestion result = new PhoneTimeZoneSuggestion(phoneId);
-        result.addDebugInfo("findTimeZoneForTestNetwork: nitzSignal=" + nitzSignal);
+        PhoneTimeZoneSuggestion.Builder suggestionBuilder =
+                new PhoneTimeZoneSuggestion.Builder(phoneId);
+        suggestionBuilder.addDebugInfo("findTimeZoneForTestNetwork: nitzSignal=" + nitzSignal);
         TimeZoneLookupHelper.OffsetResult lookupResult =
                 mTimeZoneLookupHelper.lookupByNitz(nitzData);
         if (lookupResult == null) {
-            result.addDebugInfo("findTimeZoneForTestNetwork: No zone found");
+            suggestionBuilder.addDebugInfo("findTimeZoneForTestNetwork: No zone found");
         } else {
-            result.setZoneId(lookupResult.getTimeZone().getID());
-            result.setMatchType(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY);
-            int quality = lookupResult.getIsOnlyMatch() ? PhoneTimeZoneSuggestion.SINGLE_ZONE
-                    : PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
-            result.setQuality(quality);
-            result.addDebugInfo("findTimeZoneForTestNetwork: lookupResult=" + lookupResult);
+            suggestionBuilder.setZoneId(lookupResult.getTimeZone().getID());
+            suggestionBuilder.setMatchType(
+                    PhoneTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY);
+            int quality = lookupResult.getIsOnlyMatch()
+                    ? PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE
+                    : PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+            suggestionBuilder.setQuality(quality);
+            suggestionBuilder.addDebugInfo(
+                    "findTimeZoneForTestNetwork: lookupResult=" + lookupResult);
         }
-        return result;
+        return suggestionBuilder.build();
     }
 
     /**
@@ -169,27 +170,32 @@
         Objects.requireNonNull(countryIsoCode);
         Objects.requireNonNull(nitzSignal);
 
-        PhoneTimeZoneSuggestion suggestion = new PhoneTimeZoneSuggestion(phoneId);
-        suggestion.addDebugInfo("findTimeZoneFromCountryAndNitz: countryIsoCode=" + countryIsoCode
+        PhoneTimeZoneSuggestion.Builder suggestionBuilder =
+                new PhoneTimeZoneSuggestion.Builder(phoneId);
+        suggestionBuilder.addDebugInfo("findTimeZoneFromCountryAndNitz:"
+                + " countryIsoCode=" + countryIsoCode
                 + ", nitzSignal=" + nitzSignal);
         NitzData nitzData = Objects.requireNonNull(nitzSignal.getValue());
         if (isNitzSignalOffsetInfoBogus(countryIsoCode, nitzData)) {
-            suggestion.addDebugInfo("findTimeZoneFromCountryAndNitz: NITZ signal looks bogus");
-            return suggestion;
+            suggestionBuilder.addDebugInfo(
+                    "findTimeZoneFromCountryAndNitz: NITZ signal looks bogus");
+            return suggestionBuilder.build();
         }
 
         // Try to find a match using both country + NITZ signal.
         TimeZoneLookupHelper.OffsetResult lookupResult =
                 mTimeZoneLookupHelper.lookupByNitzCountry(nitzData, countryIsoCode);
         if (lookupResult != null) {
-            suggestion.setZoneId(lookupResult.getTimeZone().getID());
-            suggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
+            suggestionBuilder.setZoneId(lookupResult.getTimeZone().getID());
+            suggestionBuilder.setMatchType(
+                    PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET);
             int quality = lookupResult.getIsOnlyMatch()
-                    ? PhoneTimeZoneSuggestion.SINGLE_ZONE
-                    : PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
-            suggestion.setQuality(quality);
-            suggestion.addDebugInfo("findTimeZoneFromCountryAndNitz: lookupResult=" + lookupResult);
-            return suggestion;
+                    ? PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE
+                    : PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+            suggestionBuilder.setQuality(quality);
+            suggestionBuilder.addDebugInfo("findTimeZoneFromCountryAndNitz:"
+                    + " lookupResult=" + lookupResult);
+            return suggestionBuilder.build();
         }
 
         // The country + offset provided no match, so see if the country by itself would be enough.
@@ -197,29 +203,29 @@
                 countryIsoCode, nitzData.getCurrentTimeInMillis());
         if (countryResult == null) {
             // Country not recognized.
-            suggestion.addDebugInfo(
+            suggestionBuilder.addDebugInfo(
                     "findTimeZoneFromCountryAndNitz: lookupByCountry() country not recognized");
-            return suggestion;
+            return suggestionBuilder.build();
         }
 
         // If the country has a single zone, or it has multiple zones but the default zone is
         // "boosted" (i.e. the country default is considered a good suggestion in most cases) then
         // use it.
-        if (countryResult.quality == QUALITY_SINGLE_ZONE
-                || countryResult.quality == QUALITY_DEFAULT_BOOSTED) {
-            suggestion.setZoneId(countryResult.zoneId);
-            suggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            suggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            suggestion.addDebugInfo(
+        if (countryResult.quality == CountryResult.QUALITY_SINGLE_ZONE
+                || countryResult.quality == CountryResult.QUALITY_DEFAULT_BOOSTED) {
+            suggestionBuilder.setZoneId(countryResult.zoneId);
+            suggestionBuilder.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+            suggestionBuilder.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+            suggestionBuilder.addDebugInfo(
                     "findTimeZoneFromCountryAndNitz: high quality country-only suggestion:"
                             + " countryResult=" + countryResult);
-            return suggestion;
+            return suggestionBuilder.build();
         }
 
         // Quality is not high enough to set the zone using country only.
-        suggestion.addDebugInfo("findTimeZoneFromCountryAndNitz: country-only suggestion quality"
-                + " not high enough. countryResult=" + countryResult);
-        return suggestion;
+        suggestionBuilder.addDebugInfo("findTimeZoneFromCountryAndNitz: country-only suggestion"
+                + " quality not high enough. countryResult=" + countryResult);
+        return suggestionBuilder.build();
     }
 
     /**
@@ -237,35 +243,39 @@
             throw new IllegalArgumentException("countryIsoCode must not be empty");
         }
 
-        PhoneTimeZoneSuggestion result = new PhoneTimeZoneSuggestion(phoneId);
-        result.addDebugInfo("findTimeZoneFromNetworkCountryCode:"
+        PhoneTimeZoneSuggestion.Builder suggestionBuilder =
+                new PhoneTimeZoneSuggestion.Builder(phoneId);
+        suggestionBuilder.addDebugInfo("findTimeZoneFromNetworkCountryCode:"
                 + " whenMillis=" + whenMillis + ", countryIsoCode=" + countryIsoCode);
         CountryResult lookupResult = mTimeZoneLookupHelper.lookupByCountry(
                 countryIsoCode, whenMillis);
         if (lookupResult != null) {
-            result.setZoneId(lookupResult.zoneId);
-            result.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
+            suggestionBuilder.setZoneId(lookupResult.zoneId);
+            suggestionBuilder.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
 
             int quality;
-            if (lookupResult.quality == QUALITY_SINGLE_ZONE
-                    || lookupResult.quality == QUALITY_DEFAULT_BOOSTED) {
-                quality = PhoneTimeZoneSuggestion.SINGLE_ZONE;
-            } else if (lookupResult.quality == QUALITY_MULTIPLE_ZONES_SAME_OFFSET) {
-                quality = PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
-            } else if (lookupResult.quality == QUALITY_MULTIPLE_ZONES_DIFFERENT_OFFSETS) {
-                quality = PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
+            if (lookupResult.quality == CountryResult.QUALITY_SINGLE_ZONE
+                    || lookupResult.quality == CountryResult.QUALITY_DEFAULT_BOOSTED) {
+                quality = PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
+            } else if (lookupResult.quality == CountryResult.QUALITY_MULTIPLE_ZONES_SAME_OFFSET) {
+                quality = PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+            } else if (lookupResult.quality
+                    == CountryResult.QUALITY_MULTIPLE_ZONES_DIFFERENT_OFFSETS) {
+                quality = PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
             } else {
                 // This should never happen.
                 throw new IllegalArgumentException(
                         "lookupResult.quality not recognized: countryIsoCode=" + countryIsoCode
                                 + ", whenMillis=" + whenMillis + ", lookupResult=" + lookupResult);
             }
-            result.setQuality(quality);
-            result.addDebugInfo("findTimeZoneFromNetworkCountryCode: lookupResult=" + lookupResult);
+            suggestionBuilder.setQuality(quality);
+            suggestionBuilder.addDebugInfo(
+                    "findTimeZoneFromNetworkCountryCode: lookupResult=" + lookupResult);
         } else {
-            result.addDebugInfo("findTimeZoneFromNetworkCountryCode: Country not recognized?");
+            suggestionBuilder.addDebugInfo(
+                    "findTimeZoneFromNetworkCountryCode: Country not recognized?");
         }
-        return result;
+        return suggestionBuilder.build();
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/nitz/service/PhoneTimeZoneSuggestion.java b/src/java/com/android/internal/telephony/nitz/service/PhoneTimeZoneSuggestion.java
deleted file mode 100644
index a5078a7..0000000
--- a/src/java/com/android/internal/telephony/nitz/service/PhoneTimeZoneSuggestion.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright 2019 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.internal.telephony.nitz.service;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * A suggested time zone from a Phone-based signal, e.g. from MCC and NITZ information.
- */
-public final class PhoneTimeZoneSuggestion implements Parcelable {
-
-    public static final Creator<PhoneTimeZoneSuggestion> CREATOR =
-            new Creator<PhoneTimeZoneSuggestion>() {
-                public PhoneTimeZoneSuggestion createFromParcel(Parcel in) {
-                    return PhoneTimeZoneSuggestion.createFromParcel(in);
-                }
-
-                public PhoneTimeZoneSuggestion[] newArray(int size) {
-                    return new PhoneTimeZoneSuggestion[size];
-                }
-            };
-
-    /**
-     * Creates an empty time zone suggestion, i.e. one that will cancel previous suggestions with
-     * the same {@code phoneId}.
-     */
-    @NonNull
-    public static PhoneTimeZoneSuggestion createEmptySuggestion(
-            int phoneId, @NonNull String debugInfo) {
-        PhoneTimeZoneSuggestion timeZoneSuggestion = new PhoneTimeZoneSuggestion(phoneId);
-        timeZoneSuggestion.addDebugInfo(debugInfo);
-        return timeZoneSuggestion;
-    }
-
-    @IntDef({ MATCH_TYPE_NA, NETWORK_COUNTRY_ONLY, NETWORK_COUNTRY_AND_OFFSET, EMULATOR_ZONE_ID,
-            TEST_NETWORK_OFFSET_ONLY })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface MatchType {}
-
-    /** Used when match type is not applicable. */
-    public static final int MATCH_TYPE_NA = 0;
-
-    /**
-     * Only the network country is known.
-     */
-    public static final int NETWORK_COUNTRY_ONLY = 2;
-
-    /**
-     * Both the network county and offset were known.
-     */
-    public static final int NETWORK_COUNTRY_AND_OFFSET = 3;
-
-    /**
-     * The device is running in an emulator and an NITZ signal was simulated containing an
-     * Android extension with an explicit Olson ID.
-     */
-    public static final int EMULATOR_ZONE_ID = 4;
-
-    /**
-     * The phone is most likely running in a test network not associated with a country (this is
-     * distinct from the country just not being known yet).
-     * Historically, Android has just picked an arbitrary time zone with the correct offset when
-     * on a test network.
-     */
-    public static final int TEST_NETWORK_OFFSET_ONLY = 5;
-
-    @IntDef({ QUALITY_NA, SINGLE_ZONE, MULTIPLE_ZONES_WITH_SAME_OFFSET,
-            MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Quality {}
-
-    /** Used when quality is not applicable. */
-    public static final int QUALITY_NA = 0;
-
-    /** There is only one answer */
-    public static final int SINGLE_ZONE = 1;
-
-    /**
-     * There are multiple answers, but they all shared the same offset / DST state at the time
-     * the suggestion was created. i.e. it might be the wrong zone but the user won't notice
-     * immediately if it is wrong.
-     */
-    public static final int MULTIPLE_ZONES_WITH_SAME_OFFSET = 2;
-
-    /**
-     * There are multiple answers with different offsets. The one given is just one possible.
-     */
-    public static final int MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS = 3;
-
-    /**
-     * The ID of the phone this suggestion is associated with. For multiple-sim devices this
-     * helps to establish origin so filtering / stickiness can be implemented.
-     */
-    private final int mPhoneId;
-
-    /**
-     * The suggestion. {@code null} means there is no current suggestion and any previous suggestion
-     * should be forgotten.
-     */
-    private String mZoneId;
-
-    /**
-     * The type of "match" used to establish the time zone.
-     */
-    @MatchType
-    private int mMatchType;
-
-    /**
-     * A measure of the quality of the time zone suggestion, i.e. how confident one could be in
-     * it.
-     */
-    @Quality
-    private int mQuality;
-
-    /**
-     * Free-form debug information about how the signal was derived. Used for debug only,
-     * intentionally not used in equals(), etc.
-     */
-    private List<String> mDebugInfo;
-
-    public PhoneTimeZoneSuggestion(int phoneId) {
-        this.mPhoneId = phoneId;
-    }
-
-    @SuppressWarnings("unchecked")
-    private static PhoneTimeZoneSuggestion createFromParcel(Parcel in) {
-        int phoneId = in.readInt();
-        PhoneTimeZoneSuggestion phoneTimeZoneSuggestion = new PhoneTimeZoneSuggestion(phoneId);
-        phoneTimeZoneSuggestion.mZoneId = in.readString();
-        phoneTimeZoneSuggestion.mMatchType = in.readInt();
-        phoneTimeZoneSuggestion.mQuality = in.readInt();
-        phoneTimeZoneSuggestion.mDebugInfo =
-                (List<String>) in.readArrayList(PhoneTimeZoneSuggestion.class.getClassLoader());
-        return phoneTimeZoneSuggestion;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mPhoneId);
-        dest.writeString(mZoneId);
-        dest.writeInt(mMatchType);
-        dest.writeInt(mQuality);
-        dest.writeList(mDebugInfo);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    public int getPhoneId() {
-        return mPhoneId;
-    }
-
-    @Nullable
-    public String getZoneId() {
-        return mZoneId;
-    }
-
-    public void setZoneId(@Nullable String zoneId) {
-        this.mZoneId = zoneId;
-    }
-
-
-    @MatchType
-    public int getMatchType() {
-        return mMatchType;
-    }
-
-    public void setMatchType(@MatchType int matchType) {
-        this.mMatchType = matchType;
-    }
-    @Quality
-    public int getQuality() {
-        return mQuality;
-    }
-
-    public void setQuality(@Quality int quality) {
-        this.mQuality = quality;
-    }
-
-    public List<String> getDebugInfo() {
-        return Collections.unmodifiableList(mDebugInfo);
-    }
-
-    /**
-     * Associates information with the instance that can be useful for debugging / logging. The
-     * information is present in {@link #toString()} but is not considered for
-     * {@link #equals(Object)} and {@link #hashCode()}.
-     */
-    public void addDebugInfo(String... debugInfos) {
-        if (mDebugInfo == null) {
-            mDebugInfo = new ArrayList<>();
-        }
-        mDebugInfo.addAll(Arrays.asList(debugInfos));
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        PhoneTimeZoneSuggestion that = (PhoneTimeZoneSuggestion) o;
-        return mPhoneId == that.mPhoneId
-                && mMatchType == that.mMatchType
-                && mQuality == that.mQuality
-                && Objects.equals(mZoneId, that.mZoneId);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mPhoneId, mZoneId, mMatchType, mQuality);
-    }
-
-    @Override
-    public String toString() {
-        return "PhoneTimeZoneSuggestion{"
-                + "mPhoneId=" + mPhoneId
-                + ", mZoneId='" + mZoneId + '\''
-                + ", mMatchType=" + mMatchType
-                + ", mQuality=" + mQuality
-                + ", mDebugInfo=" + mDebugInfo
-                + '}';
-    }
-}
diff --git a/src/java/com/android/internal/telephony/nitz/service/TimeZoneDetectionService.java b/src/java/com/android/internal/telephony/nitz/service/TimeZoneDetectionService.java
deleted file mode 100644
index a766d9a..0000000
--- a/src/java/com/android/internal/telephony/nitz/service/TimeZoneDetectionService.java
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright 2019 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.internal.telephony.nitz.service;
-
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.MATCH_TYPE_NA;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.QUALITY_NA;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.SINGLE_ZONE;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.io.PrintWriter;
-import java.util.LinkedList;
-import java.util.Objects;
-
-/**
- * A singleton, stateful time zone detection service that is aware of multiple phone devices. It
- * keeps track of the most recent suggestion from each phone and it uses the best based on a scoring
- * algorithm. If both phones provide the same score then the phone with the lowest numeric ID
- * "wins". If the situation changes and it is no longer possible to be confident about the time
- * zone, phones must submit an empty suggestion in order to "withdraw" their previous suggestion.
- *
- * <p>Ultimately, this responsibility will be moved to system server and then it will be extended /
- * rewritten to handle non-telephony time zone signals.
- */
-public class TimeZoneDetectionService {
-
-    /**
-     * Used by {@link TimeZoneDetectionService} to interact with device settings. It can be faked
-     * for tests.
-     */
-    @VisibleForTesting
-    public interface Helper {
-
-        /**
-         * Callback interface for automatic detection enable/disable changes.
-         */
-        interface Listener {
-            /**
-             * Automatic time zone detection has been enabled or disabled.
-             */
-            void onTimeZoneDetectionChange(boolean enabled);
-        }
-
-        /**
-         * Sets a listener that will be called when the automatic time / time zone detection setting
-         * changes.
-         */
-        void setListener(Listener listener);
-
-        /**
-         * Returns true if automatic time zone detection is enabled in settings.
-         */
-        boolean isTimeZoneDetectionEnabled();
-
-        /**
-         * Returns true if the device has had an explicit time zone set.
-         */
-        boolean isTimeZoneSettingInitialized();
-
-        /**
-         * Set the device time zone from the suggestion as needed.
-         */
-        void setDeviceTimeZoneFromSuggestion(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion);
-
-        /**
-         * Dumps any logs held to the supplied writer.
-         */
-        void dumpLogs(IndentingPrintWriter ipw);
-
-        /**
-         * Dumps internal state such as field values.
-         */
-        void dumpState(PrintWriter pw);
-    }
-
-    static final String LOG_TAG = "TimeZoneDetectionService";
-    static final boolean DBG = true;
-
-    /**
-     * The abstract score for an empty or invalid suggestion.
-     *
-     * Used to score suggestions where there is no zone.
-     */
-    @VisibleForTesting
-    public static final int SCORE_NONE = 0;
-
-    /**
-     * The abstract score for a low quality suggestion.
-     *
-     * Used to score suggestions where:
-     * The suggested zone ID is one of several possibilities, and the possibilities have different
-     * offsets.
-     *
-     * You would have to be quite desperate to want to use this choice.
-     */
-    @VisibleForTesting
-    public static final int SCORE_LOW = 1;
-
-    /**
-     * The abstract score for a medium quality suggestion.
-     *
-     * Used for:
-     * The suggested zone ID is one of several possibilities but at least the possibilities have the
-     * same offset. Users would get the correct time but for the wrong reason. i.e. their device may
-     * switch to DST at the wrong time and (for example) their calendar events.
-     */
-    @VisibleForTesting
-    public static final int SCORE_MEDIUM = 2;
-
-    /**
-     * The abstract score for a high quality suggestion.
-     *
-     * Used for:
-     * The suggestion was for one zone ID and the answer was unambiguous and likely correct given
-     * the info available.
-     */
-    @VisibleForTesting
-    public static final int SCORE_HIGH = 3;
-
-    /**
-     * The abstract score for a highest quality suggestion.
-     *
-     * Used for:
-     * Suggestions that must "win" because they constitute test or emulator zone ID.
-     */
-    @VisibleForTesting
-    public static final int SCORE_HIGHEST = 4;
-
-    /** The threshold at which suggestions are good enough to use to set the device's time zone. */
-    @VisibleForTesting
-    public static final int SCORE_USAGE_THRESHOLD = SCORE_MEDIUM;
-
-    /** The singleton instance. */
-    private static TimeZoneDetectionService sInstance;
-
-    /**
-     * Returns the singleton instance, constructing as needed with the supplied context.
-     */
-    public static synchronized TimeZoneDetectionService getInstance(Context context) {
-        if (sInstance == null) {
-            Helper timeZoneDetectionServiceHelper = new TimeZoneDetectionServiceHelperImpl(context);
-            sInstance = new TimeZoneDetectionService(timeZoneDetectionServiceHelper);
-        }
-        return sInstance;
-    }
-
-    private static final int KEEP_SUGGESTION_HISTORY_SIZE = 30;
-
-    /**
-     * A mapping from phoneId to a linked list of time zone suggestions (the head being the latest).
-     * We typically expect one or two entries in this Map: devices will have a small number
-     * of telephony devices and phoneIds are assumed to be stable. The LinkedList associated with
-     * the ID will not exceed {@link #KEEP_SUGGESTION_HISTORY_SIZE} in size.
-     */
-    @GuardedBy("this")
-    private ArrayMap<Integer, LinkedList<QualifiedPhoneTimeZoneSuggestion>> mSuggestionByPhoneId =
-            new ArrayMap<>();
-
-    /**
-     * The most recent best guess of time zone from all phones. Can be {@code null} to indicate
-     * there would be no current suggestion.
-     */
-    @GuardedBy("this")
-    @Nullable
-    private QualifiedPhoneTimeZoneSuggestion mCurrentSuggestion;
-
-    // Dependencies and log state.
-    private final Helper mTimeZoneDetectionServiceHelper;
-
-    @VisibleForTesting
-    public TimeZoneDetectionService(Helper timeZoneDetectionServiceHelper) {
-        mTimeZoneDetectionServiceHelper = timeZoneDetectionServiceHelper;
-        mTimeZoneDetectionServiceHelper.setListener(enabled -> {
-            if (enabled) {
-                handleAutoTimeZoneEnabled();
-            }
-        });
-    }
-
-    /**
-     * Suggests a time zone for the device, or withdraws a previous suggestion if
-     * {@link PhoneTimeZoneSuggestion#getZoneId()} is {@code null}. The suggestion is scoped to a
-     * specific {@link PhoneTimeZoneSuggestion#getPhoneId() phone}.
-     * See {@link PhoneTimeZoneSuggestion} for an explanation of the metadata associated with a
-     * suggestion. The service uses suggestions to decide whether to modify the device's time zone
-     * setting and what to set it to.
-     */
-    public synchronized void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion newSuggestion) {
-        if (DBG) {
-            Log.d(LOG_TAG, "suggestPhoneTimeZone: newSuggestion=" + newSuggestion);
-        }
-        Objects.requireNonNull(newSuggestion);
-
-        int score = scoreSuggestion(newSuggestion);
-        QualifiedPhoneTimeZoneSuggestion scoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(newSuggestion, score);
-
-        // Record the suggestion against the correct phoneId.
-        LinkedList<QualifiedPhoneTimeZoneSuggestion> suggestions =
-                mSuggestionByPhoneId.get(newSuggestion.getPhoneId());
-        if (suggestions == null) {
-            suggestions = new LinkedList<>();
-            mSuggestionByPhoneId.put(newSuggestion.getPhoneId(), suggestions);
-        }
-        suggestions.addFirst(scoredSuggestion);
-        if (suggestions.size() > KEEP_SUGGESTION_HISTORY_SIZE) {
-            suggestions.removeLast();
-        }
-
-        // Now run the competition between the phones' suggestions.
-        doTimeZoneDetection();
-    }
-
-    private static int scoreSuggestion(@NonNull PhoneTimeZoneSuggestion suggestion) {
-        int score;
-        if (suggestion.getZoneId() == null || !isValid(suggestion)) {
-            score = SCORE_NONE;
-        } else if (suggestion.getMatchType() == TEST_NETWORK_OFFSET_ONLY
-                || suggestion.getMatchType() == EMULATOR_ZONE_ID) {
-            // Handle emulator / test cases : These suggestions should always just be used.
-            score = SCORE_HIGHEST;
-        } else if (suggestion.getQuality() == SINGLE_ZONE) {
-            score = SCORE_HIGH;
-        } else if (suggestion.getQuality() == MULTIPLE_ZONES_WITH_SAME_OFFSET) {
-            // The suggestion may be wrong, but at least the offset should be correct.
-            score = SCORE_MEDIUM;
-        } else if (suggestion.getQuality() == MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS) {
-            // The suggestion has a good chance of being wrong.
-            score = SCORE_LOW;
-        } else {
-            throw new AssertionError();
-        }
-        return score;
-    }
-
-    private static boolean isValid(@NonNull PhoneTimeZoneSuggestion suggestion) {
-        int quality = suggestion.getQuality();
-        int matchType = suggestion.getMatchType();
-        if (suggestion.getZoneId() == null) {
-            return quality == QUALITY_NA && matchType == MATCH_TYPE_NA;
-        } else {
-            boolean qualityValid = quality == SINGLE_ZONE
-                    || quality == MULTIPLE_ZONES_WITH_SAME_OFFSET
-                    || quality == MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
-            boolean matchTypeValid = matchType == NETWORK_COUNTRY_ONLY
-                    || matchType == NETWORK_COUNTRY_AND_OFFSET
-                    || matchType == EMULATOR_ZONE_ID
-                    || matchType == TEST_NETWORK_OFFSET_ONLY;
-            return qualityValid && matchTypeValid;
-        }
-    }
-
-    /**
-     * Finds the best available time zone suggestion from all phones. If it is high-enough quality
-     * and automatic time zone detection is enabled then it will be set on the device. The outcome
-     * can be that this service becomes / remains un-opinionated and nothing is set.
-     */
-    @GuardedBy("this")
-    private void doTimeZoneDetection() {
-        QualifiedPhoneTimeZoneSuggestion bestSuggestion = findBestSuggestion();
-        boolean timeZoneDetectionEnabled =
-                mTimeZoneDetectionServiceHelper.isTimeZoneDetectionEnabled();
-
-        // Work out what to do with the best suggestion.
-        if (bestSuggestion == null) {
-            // There is no suggestion. Become un-opinionated.
-            if (DBG) {
-                Log.d(LOG_TAG, "doTimeZoneDetection: No good suggestion."
-                        + " bestSuggestion=null"
-                        + ", timeZoneDetectionEnabled=" + timeZoneDetectionEnabled);
-            }
-            mCurrentSuggestion = null;
-            return;
-        }
-
-        // Special case handling for uninitialized devices. This should only happen once.
-        String newZoneId = bestSuggestion.suggestion.getZoneId();
-        if (newZoneId != null && !mTimeZoneDetectionServiceHelper.isTimeZoneSettingInitialized()) {
-            Log.i(LOG_TAG, "doTimeZoneDetection: Device has no time zone set so might set the"
-                    + " device to the best available suggestion."
-                    + " bestSuggestion=" + bestSuggestion
-                    + ", timeZoneDetectionEnabled=" + timeZoneDetectionEnabled);
-
-            mCurrentSuggestion = bestSuggestion;
-            if (timeZoneDetectionEnabled) {
-                mTimeZoneDetectionServiceHelper.setDeviceTimeZoneFromSuggestion(
-                        bestSuggestion.suggestion);
-            }
-            return;
-        }
-
-        boolean suggestionGoodEnough = bestSuggestion.score >= SCORE_USAGE_THRESHOLD;
-        if (!suggestionGoodEnough) {
-            if (DBG) {
-                Log.d(LOG_TAG, "doTimeZoneDetection: Suggestion not good enough."
-                        + " bestSuggestion=" + bestSuggestion);
-            }
-            mCurrentSuggestion = null;
-            return;
-        }
-
-        // Paranoia: Every suggestion above the SCORE_USAGE_THRESHOLD should have a non-null time
-        // zone ID.
-        if (newZoneId == null) {
-            Log.w(LOG_TAG, "Empty zone suggestion scored higher than expected. This is an error:"
-                    + " bestSuggestion=" + bestSuggestion);
-            mCurrentSuggestion = null;
-            return;
-        }
-
-        // There is a good suggestion. Store the suggestion and set the device time zone if
-        // settings allow.
-        mCurrentSuggestion = bestSuggestion;
-
-        // Only set the device time zone if time zone detection is enabled.
-        if (!timeZoneDetectionEnabled) {
-            if (DBG) {
-                Log.d(LOG_TAG, "doTimeZoneDetection: Not setting the time zone because time zone"
-                        + " detection is disabled."
-                        + " bestSuggestion=" + bestSuggestion);
-            }
-            return;
-        }
-        mTimeZoneDetectionServiceHelper.setDeviceTimeZoneFromSuggestion(bestSuggestion.suggestion);
-    }
-
-    @GuardedBy("this")
-    @Nullable
-    private QualifiedPhoneTimeZoneSuggestion findBestSuggestion() {
-        QualifiedPhoneTimeZoneSuggestion bestSuggestion = null;
-
-        // Iterate over the latest QualifiedPhoneTimeZoneSuggestion objects received for each phone
-        // and find the best. Note that we deliberately do not look at age: the caller can
-        // rate-limit so age is not a strong indicator of confidence. Instead, the callers are
-        // expected to withdraw suggestions they no longer have confidence in.
-        for (int i = 0; i < mSuggestionByPhoneId.size(); i++) {
-            LinkedList<QualifiedPhoneTimeZoneSuggestion> phoneSuggestions =
-                    mSuggestionByPhoneId.valueAt(i);
-            if (phoneSuggestions == null) {
-                // Unexpected
-                continue;
-            }
-            QualifiedPhoneTimeZoneSuggestion candidateSuggestion = phoneSuggestions.getFirst();
-            if (candidateSuggestion == null) {
-                // Unexpected
-                continue;
-            }
-
-            if (bestSuggestion == null) {
-                bestSuggestion = candidateSuggestion;
-            } else if (candidateSuggestion.score > bestSuggestion.score) {
-                bestSuggestion = candidateSuggestion;
-            } else if (candidateSuggestion.score == bestSuggestion.score) {
-                // Tie! Use the suggestion with the lowest phoneId.
-                int candidatePhoneId = candidateSuggestion.suggestion.getPhoneId();
-                int bestPhoneId = bestSuggestion.suggestion.getPhoneId();
-                if (candidatePhoneId < bestPhoneId) {
-                    bestSuggestion = candidateSuggestion;
-                }
-            }
-        }
-        return bestSuggestion;
-    }
-
-    /**
-     * Returns the current best suggestion. Not intended for general use: it is used during tests
-     * to check service behavior.
-     */
-    @VisibleForTesting
-    @Nullable
-    public synchronized QualifiedPhoneTimeZoneSuggestion findBestSuggestionForTests() {
-        return findBestSuggestion();
-    }
-
-    private synchronized void handleAutoTimeZoneEnabled() {
-        if (DBG) {
-            Log.d(LOG_TAG, "handleAutoTimeEnabled() called");
-        }
-        // When the user enabled time zone detection, run the time zone detection and change the
-        // device time zone if possible.
-        doTimeZoneDetection();
-    }
-
-    /**
-     * Dumps any logs held to the supplied writer.
-     */
-    public void dumpLogs(IndentingPrintWriter ipw) {
-        mTimeZoneDetectionServiceHelper.dumpLogs(ipw);
-    }
-
-    /**
-     * Dumps internal state such as field values.
-     */
-    public void dumpState(PrintWriter pw) {
-        pw.println(" TimeZoneDetectionService.mCurrentSuggestion=" + mCurrentSuggestion);
-        pw.println(" TimeZoneDetectionService.mSuggestionsByPhoneId=" + mSuggestionByPhoneId);
-        mTimeZoneDetectionServiceHelper.dumpState(pw);
-        pw.flush();
-    }
-
-    /**
-     * A method used to inspect service state during tests. Not intended for general use.
-     */
-    @VisibleForTesting
-    public synchronized QualifiedPhoneTimeZoneSuggestion getLatestPhoneSuggestion(int phoneId) {
-        LinkedList<QualifiedPhoneTimeZoneSuggestion> suggestions =
-                mSuggestionByPhoneId.get(phoneId);
-        if (suggestions == null) {
-            return null;
-        }
-        return suggestions.getFirst();
-    }
-
-    /**
-     * A {@link PhoneTimeZoneSuggestion} with additional qualifying metadata.
-     */
-    @VisibleForTesting
-    public static class QualifiedPhoneTimeZoneSuggestion {
-
-        @VisibleForTesting
-        public final PhoneTimeZoneSuggestion suggestion;
-
-        /**
-         * The score the suggestion has been given. This can be used to rank against other
-         * suggestions of the same type.
-         */
-        @VisibleForTesting
-        public final int score;
-
-        @VisibleForTesting
-        public QualifiedPhoneTimeZoneSuggestion(PhoneTimeZoneSuggestion suggestion, int score) {
-            this.suggestion = suggestion;
-            this.score = score;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
-            QualifiedPhoneTimeZoneSuggestion that = (QualifiedPhoneTimeZoneSuggestion) o;
-            return score == that.score
-                    && suggestion.equals(that.suggestion);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(score, suggestion);
-        }
-
-        @Override
-        public String toString() {
-            return "QualifiedPhoneTimeZoneSuggestion{"
-                    + "suggestion=" + suggestion
-                    + ", score=" + score
-                    + '}';
-        }
-    }
-}
diff --git a/src/java/com/android/internal/telephony/nitz/service/TimeZoneDetectionServiceHelperImpl.java b/src/java/com/android/internal/telephony/nitz/service/TimeZoneDetectionServiceHelperImpl.java
deleted file mode 100644
index fc857a7..0000000
--- a/src/java/com/android/internal/telephony/nitz/service/TimeZoneDetectionServiceHelperImpl.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2017 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.internal.telephony.nitz.service;
-
-import android.annotation.Nullable;
-import android.app.AlarmManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.LocalLog;
-import android.util.Log;
-
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.io.PrintWriter;
-
-/**
- * The real implementation of {@link TimeZoneDetectionService.Helper}.
- */
-public final class TimeZoneDetectionServiceHelperImpl implements TimeZoneDetectionService.Helper {
-
-    private static final String LOG_TAG = TimeZoneDetectionService.LOG_TAG;
-    private static final boolean DBG = TimeZoneDetectionService.DBG;
-    private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
-
-    private final Context mContext;
-    private final ContentResolver mCr;
-    private final LocalLog mTimeZoneLog = new LocalLog(30);
-
-    private Listener mListener;
-
-    /** Creates a TimeServiceHelper */
-    public TimeZoneDetectionServiceHelperImpl(Context context) {
-        mContext = context;
-        mCr = context.getContentResolver();
-    }
-
-    @Override
-    public void setListener(Listener listener) {
-        if (listener == null) {
-            throw new NullPointerException("listener==null");
-        }
-        if (mListener != null) {
-            throw new IllegalStateException("listener already set");
-        }
-        this.mListener = listener;
-        mCr.registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
-                new ContentObserver(new Handler()) {
-                    public void onChange(boolean selfChange) {
-                        listener.onTimeZoneDetectionChange(isTimeZoneDetectionEnabled());
-                    }
-                });
-    }
-
-    @Override
-    public boolean isTimeZoneDetectionEnabled() {
-        try {
-            return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE) > 0;
-        } catch (Settings.SettingNotFoundException snfe) {
-            return true;
-        }
-    }
-
-    @Override
-    public boolean isTimeZoneSettingInitialized() {
-        // timezone.equals("GMT") will be true and only true if the time zone was
-        // set to a default value by the system server (when starting, system server
-        // sets the persist.sys.timezone to "GMT" if it's not set). "GMT" is not used by
-        // any code that sets it explicitly (in case where something sets GMT explicitly,
-        // "Etc/GMT" Olson ID would be used).
-
-        String timeZoneId = getTimeZoneSetting();
-        return timeZoneId != null && timeZoneId.length() > 0 && !timeZoneId.equals("GMT");
-    }
-
-    @Override
-    public void setDeviceTimeZoneFromSuggestion(PhoneTimeZoneSuggestion timeZoneSuggestion) {
-        String currentZoneId = getTimeZoneSetting();
-        String newZoneId = timeZoneSuggestion.getZoneId();
-        if (newZoneId.equals(currentZoneId)) {
-            // No need to set the device time zone - the setting is already what we would be
-            // suggesting.
-            if (DBG) {
-                Log.d(LOG_TAG, "setDeviceTimeZoneAsNeeded: No need to change the time zone;"
-                        + " device is already set to the suggested zone."
-                        + " timeZoneSuggestion=" + timeZoneSuggestion);
-            }
-            return;
-        }
-
-        String msg = "Changing device time zone. currentZoneId=" + currentZoneId
-                + ", timeZoneSuggestion=" + timeZoneSuggestion;
-        if (DBG) {
-            Log.d(LOG_TAG, msg);
-        }
-        mTimeZoneLog.log(msg);
-
-        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        alarmManager.setTimeZone(newZoneId);
-        Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        intent.putExtra("time-zone", newZoneId);
-        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-    }
-
-    @Nullable
-    private String getTimeZoneSetting() {
-        return SystemProperties.get(TIMEZONE_PROPERTY);
-    }
-
-    @Override
-    public void dumpState(PrintWriter pw) {
-        pw.println(" TimeZoneDetectionServiceHelperImpl.getTimeZoneSetting()="
-                + getTimeZoneSetting());
-    }
-
-    @Override
-    public void dumpLogs(IndentingPrintWriter ipw) {
-        ipw.println("TimeZoneDetectionServiceHelperImpl:");
-
-        ipw.increaseIndent();
-        ipw.println("Time zone logs:");
-        ipw.increaseIndent();
-        mTimeZoneLog.dump(ipw);
-        ipw.decreaseIndent();
-
-        ipw.decreaseIndent();
-    }
-}
diff --git a/src/java/com/android/internal/telephony/test/ModelInterpreter.java b/tests/telephonytests/src/com/android/internal/telephony/ModelInterpreter.java
similarity index 100%
rename from src/java/com/android/internal/telephony/test/ModelInterpreter.java
rename to tests/telephonytests/src/com/android/internal/telephony/ModelInterpreter.java
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTestSupport.java b/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTestSupport.java
index 72e2389..b9215ed 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTestSupport.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTestSupport.java
@@ -19,13 +19,13 @@
 import static org.junit.Assert.fail;
 
 import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
 import android.icu.util.Calendar;
 import android.icu.util.GregorianCalendar;
 import android.icu.util.TimeZone;
 import android.util.TimestampedValue;
 
 import com.android.internal.telephony.NitzStateMachine.DeviceState;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
 
 /**
  * An assortment of methods and classes for testing {@link NitzStateMachine} implementations.
@@ -272,9 +272,9 @@
     }
 
     public static PhoneTimeZoneSuggestion createEmptyTimeZoneSuggestion(int phoneId) {
-        PhoneTimeZoneSuggestion timeZoneSuggestion = new PhoneTimeZoneSuggestion(phoneId);
-        timeZoneSuggestion.addDebugInfo("Test");
-        return timeZoneSuggestion;
+        return new PhoneTimeZoneSuggestion.Builder(phoneId)
+                .addDebugInfo("Test")
+                .build();
     }
 
     public static PhoneTimeSuggestion createEmptyTimeSuggestion(int phoneId) {
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
similarity index 100%
rename from src/java/com/android/internal/telephony/test/SimulatedCommands.java
rename to tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
similarity index 99%
rename from src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
rename to tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
index c550f2c..f030a40 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
@@ -1127,7 +1127,7 @@
     }
 
     @Override
-    public void sendCDMAFeatureCode(String FeatureCode, Message response) {
+    public void sendCDMAFeatureCode(String featureCode, Message response) {
 
     }
 
@@ -1260,7 +1260,7 @@
     }
 
     @Override
-    public void iccOpenLogicalChannel(String AID, int p2, Message response) {
+    public void iccOpenLogicalChannel(String aid, int p2, Message response) {
 
     }
 
diff --git a/src/java/com/android/internal/telephony/test/SimulatedGsmCallState.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedGsmCallState.java
similarity index 100%
rename from src/java/com/android/internal/telephony/test/SimulatedGsmCallState.java
rename to tests/telephonytests/src/com/android/internal/telephony/SimulatedGsmCallState.java
diff --git a/tests/telephonytests/src/com/android/internal/telephony/nitz/NewNitzStateMachineImplTest.java b/tests/telephonytests/src/com/android/internal/telephony/nitz/NewNitzStateMachineImplTest.java
index 1c93b8c..c2419b4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/nitz/NewNitzStateMachineImplTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/nitz/NewNitzStateMachineImplTest.java
@@ -16,6 +16,9 @@
 
 package com.android.internal.telephony.nitz;
 
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+
 import static com.android.internal.telephony.NitzStateMachineTestSupport.ARBITRARY_SYSTEM_CLOCK_TIME;
 import static com.android.internal.telephony.NitzStateMachineTestSupport.UNIQUE_US_ZONE_SCENARIO1;
 import static com.android.internal.telephony.NitzStateMachineTestSupport.UNITED_KINGDOM_SCENARIO;
@@ -31,6 +34,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
 import android.util.TimestampedValue;
 
 import com.android.internal.telephony.NitzData;
@@ -39,7 +43,6 @@
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.TimeZoneLookupHelper;
 import com.android.internal.telephony.nitz.NewNitzStateMachineImpl.NitzSignalInputFilterPredicate;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
 import com.android.internal.util.IndentingPrintWriter;
 
 import org.junit.After;
@@ -212,9 +215,9 @@
         PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
                         PHONE_ID, "" /* countryIsoCode */, nitzSignal);
-        assertEquals(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY,
+        assertEquals(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY,
                 expectedTimeZoneSuggestion.getMatchType());
-        assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
+        assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET,
                 expectedTimeZoneSuggestion.getQuality());
 
         // Verify the state machine did the right thing.
@@ -256,9 +259,9 @@
         PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
                         PHONE_ID, "" /* countryIsoCode */, nitzSignal);
-        assertEquals(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY,
+        assertEquals(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY,
                 expectedTimeZoneSuggestion.getMatchType());
-        assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
+        assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET,
                 expectedTimeZoneSuggestion.getQuality());
 
         // Verify the state machine did the right thing.
diff --git a/tests/telephonytests/src/com/android/internal/telephony/nitz/TimeZoneSuggesterImplTest.java b/tests/telephonytests/src/com/android/internal/telephony/nitz/TimeZoneSuggesterImplTest.java
index cdd30e4..ef1cc0f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/nitz/TimeZoneSuggesterImplTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/nitz/TimeZoneSuggesterImplTest.java
@@ -16,6 +16,14 @@
 
 package com.android.internal.telephony.nitz;
 
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
+
 import static com.android.internal.telephony.NitzStateMachineTestSupport.ARBITRARY_REALTIME_MILLIS;
 import static com.android.internal.telephony.NitzStateMachineTestSupport.CZECHIA_SCENARIO;
 import static com.android.internal.telephony.NitzStateMachineTestSupport.NEW_ZEALAND_COUNTRY_DEFAULT_ZONE_ID;
@@ -31,6 +39,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
 import android.util.TimestampedValue;
 
 import com.android.internal.telephony.NitzData;
@@ -39,7 +48,6 @@
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.TimeZoneLookupHelper;
 import com.android.internal.telephony.nitz.NewNitzStateMachineImpl.TimeZoneSuggester;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
 
 import org.junit.After;
 import org.junit.Before;
@@ -52,7 +60,7 @@
 
     private static final int PHONE_ID = 99999;
     private static final PhoneTimeZoneSuggestion EMPTY_TIME_ZONE_SUGGESTION =
-            new PhoneTimeZoneSuggestion(PHONE_ID);
+            new PhoneTimeZoneSuggestion.Builder(PHONE_ID).build();
 
     private FakeDeviceState mFakeDeviceState;
     private TimeZoneSuggester mTimeZoneSuggester;
@@ -116,12 +124,11 @@
         // will be made.
         {
             PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(US_COUNTRY_DEFAULT_ZONE_ID);
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(US_COUNTRY_DEFAULT_ZONE_ID)
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS)
+                            .build();
 
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
@@ -135,10 +142,8 @@
                     PHONE_ID, "" /* countryIsoCode */,
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
             assertEquals(PHONE_ID, actualSuggestion.getPhoneId());
-            assertEquals(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY,
-                    actualSuggestion.getMatchType());
-            assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
-                    actualSuggestion.getQuality());
+            assertEquals(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY, actualSuggestion.getMatchType());
+            assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, actualSuggestion.getQuality());
         }
 
         // NITZ alone is not enough to get a result when the country is not available.
@@ -152,12 +157,11 @@
         // Country + NITZ is enough for a unique time zone detection result for this scenario.
         {
             PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(),
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
@@ -192,12 +196,11 @@
         // will be made.
         {
             PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(US_COUNTRY_DEFAULT_ZONE_ID);
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(US_COUNTRY_DEFAULT_ZONE_ID)
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS)
+                            .build();
 
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
@@ -211,10 +214,8 @@
                     PHONE_ID, "" /* countryIsoCode */,
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
             assertEquals(PHONE_ID, actualSuggestion.getPhoneId());
-            assertEquals(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY,
-                    actualSuggestion.getMatchType());
-            assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
-                    actualSuggestion.getQuality());
+            assertEquals(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY, actualSuggestion.getMatchType());
+            assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, actualSuggestion.getQuality());
         }
 
         // NITZ alone is not enough to get a result when the country is not available.
@@ -231,10 +232,8 @@
                     PHONE_ID, scenario.getNetworkCountryIsoCode(),
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
             assertEquals(PHONE_ID, actualSuggestion.getPhoneId());
-            assertEquals(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET,
-                    actualSuggestion.getMatchType());
-            assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
-                    actualSuggestion.getQuality());
+            assertEquals(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, actualSuggestion.getMatchType());
+            assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, actualSuggestion.getQuality());
             List<String> allowedZoneIds = Arrays.asList(NON_UNIQUE_US_ZONE_SCENARIO_ZONES);
             assertTrue(allowedZoneIds.contains(actualSuggestion.getZoneId()));
         }
@@ -266,12 +265,11 @@
         // Country alone is enough to guess the time zone.
         {
             PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
 
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
@@ -285,10 +283,8 @@
                     PHONE_ID, "" /* countryIsoCode */,
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
             assertEquals(PHONE_ID, actualSuggestion.getPhoneId());
-            assertEquals(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY,
-                    actualSuggestion.getMatchType());
-            assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
-                    actualSuggestion.getQuality());
+            assertEquals(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY, actualSuggestion.getMatchType());
+            assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, actualSuggestion.getQuality());
 
         }
 
@@ -303,12 +299,12 @@
         // Country + NITZ is enough for both time + time zone detection.
         {
             PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(),
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
@@ -322,12 +318,12 @@
             TimestampedValue<NitzData> badNitzSignal =
                     CZECHIA_SCENARIO.createNitzSignal(mFakeDeviceState.elapsedRealtime());
             PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(),
                     badNitzSignal);
@@ -347,12 +343,11 @@
         // Country alone is enough to guess the time zone.
         {
             PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
 
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
@@ -367,10 +362,8 @@
                             PHONE_ID, "" /* countryIsoCode */,
                             scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
             assertEquals(PHONE_ID, actualSuggestion.getPhoneId());
-            assertEquals(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY,
-                    actualSuggestion.getMatchType());
-            assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
-                    actualSuggestion.getQuality());
+            assertEquals(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY, actualSuggestion.getMatchType());
+            assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, actualSuggestion.getQuality());
 
         }
 
@@ -385,12 +378,12 @@
         // Country + NITZ is enough for both time + time zone detection.
         {
             PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(),
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
@@ -404,12 +397,12 @@
             TimestampedValue<NitzData> badNitzSignal =
                     UNIQUE_US_ZONE_SCENARIO1.createNitzSignal(mFakeDeviceState.elapsedRealtime());
             PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(),
                     badNitzSignal);
@@ -424,12 +417,11 @@
         // Country alone is enough to guess the time zone.
         {
             PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
 
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
@@ -461,12 +453,11 @@
         // Country alone is not enough to guess the time zone.
         {
             PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(US_COUNTRY_DEFAULT_ZONE_ID);
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(US_COUNTRY_DEFAULT_ZONE_ID)
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS)
+                            .build();
 
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
@@ -513,10 +504,11 @@
                 originalNitzSignal.getReferenceTimeMillis(), emulatorNitzData);
 
         PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                new PhoneTimeZoneSuggestion(PHONE_ID);
-        expectedTimeZoneSuggestion.setZoneId(emulatorTimeZoneId);
-        expectedTimeZoneSuggestion.setMatchType(PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID);
-        expectedTimeZoneSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
+                new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                        .setZoneId(emulatorTimeZoneId)
+                        .setMatchType(MATCH_TYPE_EMULATOR_ZONE_ID)
+                        .setQuality(QUALITY_SINGLE_ZONE)
+                        .build();
 
         PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                 PHONE_ID, scenario.getNetworkCountryIsoCode(), emulatorNitzSignal);
@@ -529,10 +521,13 @@
         // countryIsoCode.
         {
             Scenario scenario = NEW_ZEALAND_DEFAULT_SCENARIO;
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(NEW_ZEALAND_COUNTRY_DEFAULT_ZONE_ID);
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
+            PhoneTimeZoneSuggestion expectedSuggestion =
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(NEW_ZEALAND_COUNTRY_DEFAULT_ZONE_ID)
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
             assertEquals(expectedSuggestion, actualSuggestion);
@@ -543,10 +538,13 @@
             Scenario scenario = NEW_ZEALAND_DEFAULT_SCENARIO;
             TimestampedValue<NitzData> nitzSignal =
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
+            PhoneTimeZoneSuggestion expectedSuggestion =
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), nitzSignal);
             assertEquals(expectedSuggestion, actualSuggestion);
@@ -557,10 +555,13 @@
             Scenario scenario = NEW_ZEALAND_OTHER_SCENARIO;
             TimestampedValue<NitzData> nitzSignal =
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
+            PhoneTimeZoneSuggestion expectedSuggestion =
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), nitzSignal);
             assertEquals(expectedSuggestion, actualSuggestion);
@@ -573,10 +574,13 @@
             // Use a scenario that has a different offset than NZ to generate the NITZ signal.
             TimestampedValue<NitzData> nitzSignal =
                     CZECHIA_SCENARIO.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(NEW_ZEALAND_COUNTRY_DEFAULT_ZONE_ID);
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
+            PhoneTimeZoneSuggestion expectedSuggestion =
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(NEW_ZEALAND_COUNTRY_DEFAULT_ZONE_ID)
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), nitzSignal);
             assertEquals(expectedSuggestion, actualSuggestion);
@@ -589,11 +593,13 @@
         // we cannot get a zone only from the countryIsoCode.
         {
             Scenario scenario = UNIQUE_US_ZONE_SCENARIO1;
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(US_COUNTRY_DEFAULT_ZONE_ID);
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+            PhoneTimeZoneSuggestion expectedSuggestion =
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(US_COUNTRY_DEFAULT_ZONE_ID)
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS)
+                            .build();
+
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
             assertEquals(expectedSuggestion, actualSuggestion);
@@ -604,10 +610,13 @@
             Scenario scenario = UNIQUE_US_ZONE_SCENARIO1;
             TimestampedValue<NitzData> nitzSignal =
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
+            PhoneTimeZoneSuggestion expectedSuggestion =
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), nitzSignal);
             assertEquals(expectedSuggestion, actualSuggestion);
@@ -618,10 +627,13 @@
             Scenario scenario = UNIQUE_US_ZONE_SCENARIO2;
             TimestampedValue<NitzData> nitzSignal =
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
+            PhoneTimeZoneSuggestion expectedSuggestion =
+                    new PhoneTimeZoneSuggestion.Builder(PHONE_ID)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
             PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
                     PHONE_ID, scenario.getNetworkCountryIsoCode(), nitzSignal);
             assertEquals(expectedSuggestion, actualSuggestion);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/nitz/service/PhoneTimeZoneSuggestionTest.java b/tests/telephonytests/src/com/android/internal/telephony/nitz/service/PhoneTimeZoneSuggestionTest.java
deleted file mode 100644
index 54838ae..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/nitz/service/PhoneTimeZoneSuggestionTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2019 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.internal.telephony.nitz.service;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import org.junit.Test;
-
-public class PhoneTimeZoneSuggestionTest {
-    private static final int PHONE_ID = 99999;
-
-    @Test
-    public void testEquals() {
-        PhoneTimeZoneSuggestion one = new PhoneTimeZoneSuggestion(PHONE_ID);
-        assertEquals(one, one);
-
-        PhoneTimeZoneSuggestion two = new PhoneTimeZoneSuggestion(PHONE_ID);
-        assertEquals(one, two);
-        assertEquals(two, one);
-
-        PhoneTimeZoneSuggestion three = new PhoneTimeZoneSuggestion(PHONE_ID + 1);
-        assertNotEquals(one, three);
-        assertNotEquals(three, one);
-
-        one.setZoneId("Europe/London");
-        assertNotEquals(one, two);
-        two.setZoneId("Europe/Paris");
-        assertNotEquals(one, two);
-        one.setZoneId(two.getZoneId());
-        assertEquals(one, two);
-
-        one.setMatchType(PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID);
-        two.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-        assertNotEquals(one, two);
-        one.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-        assertEquals(one, two);
-
-        one.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-        two.setQuality(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
-        assertNotEquals(one, two);
-        one.setQuality(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
-        assertEquals(one, two);
-
-        // DebugInfo must not be considered in equals().
-        one.addDebugInfo("Debug info 1");
-        two.addDebugInfo("Debug info 2");
-        assertEquals(one, two);
-    }
-
-    @Test
-    public void testParcelable() {
-        PhoneTimeZoneSuggestion one = new PhoneTimeZoneSuggestion(PHONE_ID);
-        assertEquals(one, roundTripParcelable(one));
-
-        one.setZoneId("Europe/London");
-        one.setMatchType(PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID);
-        one.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-        assertEquals(one, roundTripParcelable(one));
-
-        // DebugInfo should also be stored (but is not checked by equals()
-        one.addDebugInfo("This is debug info");
-        PhoneTimeZoneSuggestion two = roundTripParcelable(one);
-        assertEquals(one.getDebugInfo(), two.getDebugInfo());
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T extends Parcelable> T roundTripParcelable(T one) {
-        Parcel parcel = Parcel.obtain();
-        parcel.writeTypedObject(one, 0);
-        parcel.setDataPosition(0);
-
-        T toReturn = (T) parcel.readTypedObject(PhoneTimeZoneSuggestion.CREATOR);
-        parcel.recycle();
-        return toReturn;
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/nitz/service/TimeZoneDetectionServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/nitz/service/TimeZoneDetectionServiceTest.java
deleted file mode 100644
index f268501..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/nitz/service/TimeZoneDetectionServiceTest.java
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * Copyright 2019 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.internal.telephony.nitz.service;
-
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.SINGLE_ZONE;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY;
-import static com.android.internal.telephony.nitz.service.TimeZoneDetectionService.SCORE_HIGH;
-import static com.android.internal.telephony.nitz.service.TimeZoneDetectionService.SCORE_HIGHEST;
-import static com.android.internal.telephony.nitz.service.TimeZoneDetectionService.SCORE_LOW;
-import static com.android.internal.telephony.nitz.service.TimeZoneDetectionService.SCORE_MEDIUM;
-import static com.android.internal.telephony.nitz.service.TimeZoneDetectionService.SCORE_NONE;
-import static com.android.internal.telephony.nitz.service.TimeZoneDetectionService.SCORE_USAGE_THRESHOLD;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.MatchType;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.Quality;
-import com.android.internal.telephony.nitz.service.TimeZoneDetectionService.QualifiedPhoneTimeZoneSuggestion;
-import com.android.internal.util.IndentingPrintWriter;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedList;
-
-/**
- * White-box unit tests for {@link TimeZoneDetectionService}.
- */
-public class TimeZoneDetectionServiceTest {
-
-    private static final int PHONE1_ID = 10000;
-    private static final int PHONE2_ID = 20000;
-
-    // Suggestion test cases are ordered so that each successive one is of the same or higher score
-    // than the previous.
-    private static final SuggestionTestCase[] TEST_CASES = new SuggestionTestCase[] {
-            newTestCase(NETWORK_COUNTRY_ONLY, MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, SCORE_LOW),
-            newTestCase(NETWORK_COUNTRY_ONLY, MULTIPLE_ZONES_WITH_SAME_OFFSET, SCORE_MEDIUM),
-            newTestCase(NETWORK_COUNTRY_AND_OFFSET, MULTIPLE_ZONES_WITH_SAME_OFFSET, SCORE_MEDIUM),
-            newTestCase(NETWORK_COUNTRY_ONLY, SINGLE_ZONE, SCORE_HIGH),
-            newTestCase(NETWORK_COUNTRY_AND_OFFSET, SINGLE_ZONE, SCORE_HIGH),
-            newTestCase(TEST_NETWORK_OFFSET_ONLY, MULTIPLE_ZONES_WITH_SAME_OFFSET, SCORE_HIGHEST),
-            newTestCase(EMULATOR_ZONE_ID, SINGLE_ZONE, SCORE_HIGHEST),
-    };
-
-    private TimeZoneDetectionService mTimeZoneDetectionService;
-    private FakeTimeZoneDetectionServiceHelper mFakeTimeZoneDetectionServiceHelper;
-
-    @Before
-    public void setUp() {
-        mFakeTimeZoneDetectionServiceHelper = new FakeTimeZoneDetectionServiceHelper();
-        mTimeZoneDetectionService =
-                new TimeZoneDetectionService(mFakeTimeZoneDetectionServiceHelper);
-    }
-
-    @Test
-    public void testEmptySuggestions() {
-        PhoneTimeZoneSuggestion phone1TimeZoneSuggestion = createEmptyPhone1Suggestion();
-        PhoneTimeZoneSuggestion phone2TimeZoneSuggestion = createEmptyPhone2Suggestion();
-        Script script = new Script()
-                .initializeTimeZoneDetectionEnabled(true)
-                .initializeTimeZoneSetting(true);
-
-        script.suggestPhoneTimeZone(phone1TimeZoneSuggestion)
-                .verifyTimeZoneNotSet();
-
-        // Assert internal service state.
-        QualifiedPhoneTimeZoneSuggestion expectedPhone1ScoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(phone1TimeZoneSuggestion, SCORE_NONE);
-        assertEquals(expectedPhone1ScoredSuggestion,
-                mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-        assertNull(mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE2_ID));
-        assertEquals(expectedPhone1ScoredSuggestion,
-                mTimeZoneDetectionService.findBestSuggestionForTests());
-
-        script.suggestPhoneTimeZone(phone2TimeZoneSuggestion)
-                .verifyTimeZoneNotSet();
-
-        // Assert internal service state.
-        QualifiedPhoneTimeZoneSuggestion expectedPhone2ScoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(phone2TimeZoneSuggestion, SCORE_NONE);
-        assertEquals(expectedPhone1ScoredSuggestion,
-                mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-        assertEquals(expectedPhone2ScoredSuggestion,
-                mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE2_ID));
-        // Phone 1 should always beat phone 2, all other things being equal.
-        assertEquals(expectedPhone1ScoredSuggestion,
-                mTimeZoneDetectionService.findBestSuggestionForTests());
-    }
-
-    @Test
-    public void testFirstPlausibleSuggestionAcceptedWhenTimeZoneUninitialized() {
-        SuggestionTestCase testCase =
-                newTestCase(NETWORK_COUNTRY_ONLY, MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, SCORE_LOW);
-        PhoneTimeZoneSuggestion lowQualitySuggestion =
-                testCase.createSuggestion(PHONE1_ID, "America/New_York");
-        Script script = new Script()
-                .initializeTimeZoneDetectionEnabled(true);
-
-        // The device is uninitialized.
-        script.initializeTimeZoneSetting(false);
-
-        // The very first suggestion will be taken.
-        script.suggestPhoneTimeZone(lowQualitySuggestion)
-                .verifyTimeZoneSetAndReset(lowQualitySuggestion);
-
-        // Assert internal service state.
-        QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(lowQualitySuggestion, testCase.expectedScore);
-        assertEquals(expectedScoredSuggestion,
-                mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-        assertEquals(expectedScoredSuggestion,
-                mTimeZoneDetectionService.findBestSuggestionForTests());
-
-        // Another low quality suggestion will be ignored now that the setting is initialized.
-        PhoneTimeZoneSuggestion lowQualitySuggestion2 =
-                testCase.createSuggestion(PHONE1_ID, "America/Los_Angeles");
-        script.suggestPhoneTimeZone(lowQualitySuggestion2)
-                .verifyTimeZoneNotSet();
-
-        // Assert internal service state.
-        QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion2 =
-                new QualifiedPhoneTimeZoneSuggestion(lowQualitySuggestion2, testCase.expectedScore);
-        assertEquals(expectedScoredSuggestion2,
-                mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-        assertEquals(expectedScoredSuggestion2,
-                mTimeZoneDetectionService.findBestSuggestionForTests());
-    }
-
-    @Test
-    public void testTogglingTimeZoneDetection() {
-        Script script = new Script()
-                .initializeTimeZoneSetting(true);
-
-        boolean timeZoneDetectionEnabled = false;
-        script.initializeTimeZoneDetectionEnabled(timeZoneDetectionEnabled);
-
-        for (int i = 0; i < TEST_CASES.length; i++) {
-            SuggestionTestCase testCase = TEST_CASES[i];
-
-            PhoneTimeZoneSuggestion suggestion =
-                    testCase.createSuggestion(PHONE1_ID, "Europe/London");
-            script.suggestPhoneTimeZone(suggestion);
-
-            // When time zone detection is already enabled the suggestion (if it scores highly
-            // enough) should be set immediately.
-            if (timeZoneDetectionEnabled) {
-                if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
-                    script.verifyTimeZoneSetAndReset(suggestion);
-                } else {
-                    script.verifyTimeZoneNotSet();
-                }
-            } else {
-                script.verifyTimeZoneNotSet();
-            }
-
-            // Assert internal service state.
-            QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion =
-                    new QualifiedPhoneTimeZoneSuggestion(suggestion, testCase.expectedScore);
-            assertEquals(expectedScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-            assertEquals(expectedScoredSuggestion,
-                    mTimeZoneDetectionService.findBestSuggestionForTests());
-
-            // Now toggle the time zone detection setting: when it is toggled to on and the most
-            // recent suggestion scores highly enough, the time zone should be set.
-            timeZoneDetectionEnabled = !timeZoneDetectionEnabled;
-            script.timeZoneDetectionEnabled(timeZoneDetectionEnabled);
-            if (timeZoneDetectionEnabled) {
-                if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
-                    script.verifyTimeZoneSetAndReset(suggestion);
-                } else {
-                    script.verifyTimeZoneNotSet();
-                }
-            } else {
-                script.verifyTimeZoneNotSet();
-            }
-
-            // Assert internal service state.
-            assertEquals(expectedScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-            assertEquals(expectedScoredSuggestion,
-                    mTimeZoneDetectionService.findBestSuggestionForTests());
-        }
-    }
-
-    @Test
-    public void testSuggestionsSinglePhone() {
-        Script script = new Script()
-                .initializeTimeZoneDetectionEnabled(true)
-                .initializeTimeZoneSetting(true);
-
-        for (SuggestionTestCase testCase : TEST_CASES) {
-            makePhone1SuggestionAndCheckState(script, testCase);
-        }
-
-        /*
-         * This is the same test as above but the test cases are in
-         * reverse order of their expected score. New suggestions always replace previous ones:
-         * there's effectively no history and so ordering shouldn't make any difference.
-         */
-
-        // Each test case will have the same or lower score than the last.
-        ArrayList<SuggestionTestCase> descendingCasesByScore =
-                new ArrayList<>(Arrays.asList(TEST_CASES));
-        Collections.reverse(descendingCasesByScore);
-
-        for (SuggestionTestCase testCase : descendingCasesByScore) {
-            makePhone1SuggestionAndCheckState(script, testCase);
-        }
-    }
-
-    private void makePhone1SuggestionAndCheckState(Script script, SuggestionTestCase testCase) {
-        String zoneId = "Europe/London";
-        PhoneTimeZoneSuggestion zonePhone1Suggestion = testCase.createSuggestion(PHONE1_ID, zoneId);
-        QualifiedPhoneTimeZoneSuggestion expectedZonePhone1ScoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(zonePhone1Suggestion, testCase.expectedScore);
-
-        script.suggestPhoneTimeZone(zonePhone1Suggestion);
-        if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
-            script.verifyTimeZoneSetAndReset(zonePhone1Suggestion);
-        } else {
-            script.verifyTimeZoneNotSet();
-        }
-
-        // Assert internal service state.
-        assertEquals(expectedZonePhone1ScoredSuggestion,
-                mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-        assertEquals(expectedZonePhone1ScoredSuggestion,
-                mTimeZoneDetectionService.findBestSuggestionForTests());
-    }
-
-    /**
-     * Tries a set of test cases to see if the phone with the lowest ID is given preference. This
-     * test also confirms that the time zone setting would only be set if a suggestion is of
-     * sufficient quality.
-     */
-    @Test
-    public void testMultiplePhoneSuggestionScoringAndPhoneIdBias() {
-        String[] zoneIds = { "Europe/London", "Europe/Paris" };
-        PhoneTimeZoneSuggestion emptyPhone1Suggestion = createEmptyPhone1Suggestion();
-        PhoneTimeZoneSuggestion emptyPhone2Suggestion = createEmptyPhone2Suggestion();
-        QualifiedPhoneTimeZoneSuggestion expectedEmptyPhone1ScoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(emptyPhone1Suggestion, SCORE_NONE);
-        QualifiedPhoneTimeZoneSuggestion expectedEmptyPhone2ScoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(emptyPhone2Suggestion, SCORE_NONE);
-
-        Script script = new Script()
-                .initializeTimeZoneDetectionEnabled(true)
-                .initializeTimeZoneSetting(true)
-                // Initialize the latest suggestions as empty so we don't need to worry about nulls
-                // below for the first loop.
-                .suggestPhoneTimeZone(emptyPhone1Suggestion)
-                .suggestPhoneTimeZone(emptyPhone2Suggestion)
-                .resetState();
-
-        for (SuggestionTestCase testCase : TEST_CASES) {
-            PhoneTimeZoneSuggestion zonePhone1Suggestion =
-                    testCase.createSuggestion(PHONE1_ID, zoneIds[0]);
-            PhoneTimeZoneSuggestion zonePhone2Suggestion =
-                    testCase.createSuggestion(PHONE2_ID, zoneIds[1]);
-            QualifiedPhoneTimeZoneSuggestion expectedZonePhone1ScoredSuggestion =
-                    new QualifiedPhoneTimeZoneSuggestion(zonePhone1Suggestion,
-                            testCase.expectedScore);
-            QualifiedPhoneTimeZoneSuggestion expectedZonePhone2ScoredSuggestion =
-                    new QualifiedPhoneTimeZoneSuggestion(zonePhone2Suggestion,
-                            testCase.expectedScore);
-
-            // Start the test by making a suggestion for phone 1.
-            script.suggestPhoneTimeZone(zonePhone1Suggestion);
-            if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
-                script.verifyTimeZoneSetAndReset(zonePhone1Suggestion);
-            } else {
-                script.verifyTimeZoneNotSet();
-            }
-
-            // Assert internal service state.
-            assertEquals(expectedZonePhone1ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-            assertEquals(expectedEmptyPhone2ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE2_ID));
-            assertEquals(expectedZonePhone1ScoredSuggestion,
-                    mTimeZoneDetectionService.findBestSuggestionForTests());
-
-            // Phone 2 then makes an identical suggestion. Phone 1's suggestion should still "win"
-            // if it is above the required threshold.
-            script.suggestPhoneTimeZone(zonePhone2Suggestion);
-            if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
-                script.verifyTimeZoneSetAndReset(zonePhone1Suggestion);
-            } else {
-                script.verifyTimeZoneNotSet();
-            }
-
-            // Assert internal service state.
-            assertEquals(expectedZonePhone1ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-            assertEquals(expectedZonePhone2ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE2_ID));
-            // Phone 1 should always beat phone 2, all other things being equal.
-            assertEquals(expectedZonePhone1ScoredSuggestion,
-                    mTimeZoneDetectionService.findBestSuggestionForTests());
-
-            // Withdrawing phone 1's suggestion should leave phone 2 as the new winner. Since the
-            // zoneId is different, the time zone setting should be updated.
-            script.suggestPhoneTimeZone(emptyPhone1Suggestion);
-            if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
-                script.verifyTimeZoneSetAndReset(zonePhone2Suggestion);
-            } else {
-                script.verifyTimeZoneNotSet();
-            }
-
-            // Assert internal service state.
-            assertEquals(expectedEmptyPhone1ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-            assertEquals(expectedZonePhone2ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE2_ID));
-            assertEquals(expectedZonePhone2ScoredSuggestion,
-                    mTimeZoneDetectionService.findBestSuggestionForTests());
-
-            // Reset the state for the next loop.
-            script.suggestPhoneTimeZone(emptyPhone2Suggestion)
-                    .verifyTimeZoneNotSet();
-            assertEquals(expectedEmptyPhone1ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-            assertEquals(expectedEmptyPhone2ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE2_ID));
-        }
-    }
-
-    /**
-     * The {@link TimeZoneDetectionService.Helper} is left to detect whether changing the the time
-     * zone is actually necessary. This test proves that the service doesn't assume it knows the
-     * current setting.
-     */
-    @Test
-    public void testTimeZoneDetectionServiceDoesNotAssumeCurrentSetting() {
-        Script script = new Script()
-                .initializeTimeZoneDetectionEnabled(true);
-
-        SuggestionTestCase testCase =
-                newTestCase(NETWORK_COUNTRY_AND_OFFSET, SINGLE_ZONE, SCORE_HIGH);
-        PhoneTimeZoneSuggestion losAngelesSuggestion =
-                testCase.createSuggestion(PHONE1_ID, "America/Los_Angeles");
-        PhoneTimeZoneSuggestion newYorkSuggestion =
-                testCase.createSuggestion(PHONE1_ID, "America/New_York");
-
-        // Initialization.
-        script.suggestPhoneTimeZone(losAngelesSuggestion)
-                .verifyTimeZoneSetAndReset(losAngelesSuggestion);
-        // Suggest it again - it should be set.
-        script.suggestPhoneTimeZone(losAngelesSuggestion)
-                .verifyTimeZoneSetAndReset(losAngelesSuggestion);
-
-        // Toggling time zone detection should set it.
-        script.timeZoneDetectionEnabled(false)
-                .timeZoneDetectionEnabled(true)
-                .verifyTimeZoneSetAndReset(losAngelesSuggestion);
-
-        // Simulate a user turning detection off, a new suggestion being made, and the user turning
-        // it on again.
-        script.timeZoneDetectionEnabled(false)
-                .suggestPhoneTimeZone(newYorkSuggestion)
-                .verifyTimeZoneNotSet();
-        // Latest suggestion should be used.
-        script.timeZoneDetectionEnabled(true)
-                .verifyTimeZoneSetAndReset(newYorkSuggestion);
-    }
-
-    private static PhoneTimeZoneSuggestion createEmptyPhone1Suggestion() {
-        return new PhoneTimeZoneSuggestion(PHONE1_ID);
-    }
-
-    private static PhoneTimeZoneSuggestion createEmptyPhone2Suggestion() {
-        return new PhoneTimeZoneSuggestion(PHONE2_ID);
-    }
-
-    class FakeTimeZoneDetectionServiceHelper implements TimeZoneDetectionService.Helper {
-
-        private Listener mListener;
-        private boolean mTimeZoneDetectionEnabled;
-        private boolean mTimeZoneInitialized = false;
-        private TestState<PhoneTimeZoneSuggestion> mTimeZoneSuggestion = new TestState<>();
-
-        @Override
-        public void setListener(Listener listener) {
-            this.mListener = listener;
-        }
-
-        @Override
-        public boolean isTimeZoneDetectionEnabled() {
-            return mTimeZoneDetectionEnabled;
-        }
-
-        @Override
-        public boolean isTimeZoneSettingInitialized() {
-            return mTimeZoneInitialized;
-        }
-
-        @Override
-        public void setDeviceTimeZoneFromSuggestion(PhoneTimeZoneSuggestion timeZoneSuggestion) {
-            mTimeZoneInitialized = true;
-            mTimeZoneSuggestion.set(timeZoneSuggestion);
-        }
-
-        @Override
-        public void dumpState(PrintWriter pw) {
-            // No-op for fake
-        }
-
-        @Override
-        public void dumpLogs(IndentingPrintWriter ipw) {
-            // No-op for fake
-        }
-
-        void initializeTimeZoneDetectionEnabled(boolean enabled) {
-            mTimeZoneDetectionEnabled = enabled;
-        }
-
-        void initializeTimeZone(boolean initialized) {
-            mTimeZoneInitialized = initialized;
-        }
-
-        void simulateTimeZoneDetectionEnabled(boolean enabled) {
-            mTimeZoneDetectionEnabled = enabled;
-            mListener.onTimeZoneDetectionChange(enabled);
-        }
-
-        void assertTimeZoneNotSet() {
-            mTimeZoneSuggestion.assertHasNotBeenSet();
-        }
-
-        void assertTimeZoneSuggested(PhoneTimeZoneSuggestion timeZoneSuggestion) {
-            mTimeZoneSuggestion.assertHasBeenSet();
-            mTimeZoneSuggestion.assertChangeCount(1);
-            mTimeZoneSuggestion.assertLatestEquals(timeZoneSuggestion);
-        }
-
-        void commitAllChanges() {
-            mTimeZoneSuggestion.commitLatest();
-        }
-    }
-
-    /** Some piece of state that tests want to track. */
-    private static class TestState<T> {
-        private T mInitialValue;
-        private LinkedList<T> mValues = new LinkedList<>();
-
-        void init(T value) {
-            mValues.clear();
-            mInitialValue = value;
-        }
-
-        void set(T value) {
-            mValues.addFirst(value);
-        }
-
-        boolean hasBeenSet() {
-            return mValues.size() > 0;
-        }
-
-        void assertHasNotBeenSet() {
-            assertFalse(hasBeenSet());
-        }
-
-        void assertHasBeenSet() {
-            assertTrue(hasBeenSet());
-        }
-
-        void commitLatest() {
-            if (hasBeenSet()) {
-                mInitialValue = mValues.getLast();
-                mValues.clear();
-            }
-        }
-
-        void assertLatestEquals(T expected) {
-            assertEquals(expected, getLatest());
-        }
-
-        void assertChangeCount(int expectedCount) {
-            assertEquals(expectedCount, mValues.size());
-        }
-
-        public T getLatest() {
-            if (hasBeenSet()) {
-                return mValues.getFirst();
-            }
-            return mInitialValue;
-        }
-    }
-
-    /**
-     * A "fluent" class allows reuse of code in tests: initialization, simulation and verification
-     * logic.
-     */
-    private class Script {
-
-        Script initializeTimeZoneDetectionEnabled(boolean enabled) {
-            mFakeTimeZoneDetectionServiceHelper.initializeTimeZoneDetectionEnabled(enabled);
-            return this;
-        }
-
-        Script initializeTimeZoneSetting(boolean initialized) {
-            mFakeTimeZoneDetectionServiceHelper.initializeTimeZone(initialized);
-            return this;
-        }
-
-        Script timeZoneDetectionEnabled(boolean timeZoneDetectionEnabled) {
-            mFakeTimeZoneDetectionServiceHelper.simulateTimeZoneDetectionEnabled(
-                    timeZoneDetectionEnabled);
-            return this;
-        }
-
-        /** Simulates the time zone detection service receiving a phone-originated suggestion. */
-        Script suggestPhoneTimeZone(PhoneTimeZoneSuggestion phoneTimeZoneSuggestion) {
-            mTimeZoneDetectionService.suggestPhoneTimeZone(phoneTimeZoneSuggestion);
-            return this;
-        }
-
-        Script verifyTimeZoneNotSet() {
-            mFakeTimeZoneDetectionServiceHelper.assertTimeZoneNotSet();
-            return this;
-        }
-
-        Script verifyTimeZoneSetAndReset(PhoneTimeZoneSuggestion timeZoneSuggestion) {
-            mFakeTimeZoneDetectionServiceHelper.assertTimeZoneSuggested(timeZoneSuggestion);
-            mFakeTimeZoneDetectionServiceHelper.commitAllChanges();
-            return this;
-        }
-
-        Script resetState() {
-            mFakeTimeZoneDetectionServiceHelper.commitAllChanges();
-            return this;
-        }
-    }
-
-    private static class SuggestionTestCase {
-        public final int matchType;
-        public final int quality;
-        public final int expectedScore;
-
-        SuggestionTestCase(int matchType, int quality, int expectedScore) {
-            this.matchType = matchType;
-            this.quality = quality;
-            this.expectedScore = expectedScore;
-        }
-
-        private PhoneTimeZoneSuggestion createSuggestion(int phoneId, String zoneId) {
-            PhoneTimeZoneSuggestion suggestion = new PhoneTimeZoneSuggestion(phoneId);
-            suggestion.setZoneId(zoneId);
-            suggestion.setMatchType(matchType);
-            suggestion.setQuality(quality);
-            return suggestion;
-        }
-    }
-
-    private static SuggestionTestCase newTestCase(
-            @MatchType int matchType, @Quality int quality, int expectedScore) {
-        return new SuggestionTestCase(matchType, quality, expectedScore);
-    }
-}