Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d7d1bdc authored by Neil Fuller's avatar Neil Fuller Committed by Android (Google) Code Review
Browse files

Merge "Move time zone detection logic to system server"

parents e42bdd61 fc1d073b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.internal.telephony.nitz;
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.NitzData;
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 @@ public final class NewNitzStateMachineImpl implements NitzStateMachine {
            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
+1 −1
Original line number Diff line number Diff line
@@ -19,8 +19,8 @@ package com.android.internal.telephony.nitz;
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;
+5 −8
Original line number Diff line number Diff line
@@ -20,14 +20,14 @@ import android.annotation.NonNull;
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 @@ public final class NewTimeServiceHelperImpl implements NewTimeServiceHelper {

    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 @@ public final class NewTimeServiceHelperImpl implements NewTimeServiceHelper {
        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 @@ public final class NewTimeServiceHelperImpl implements NewTimeServiceHelper {
        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);
    }
}
+70 −60
Original line number Diff line number Diff line
@@ -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.NitzStateMachine.DeviceState;
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 @@ public class TimeZoneSuggesterImpl implements TimeZoneSuggester {
            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 @@ public class TimeZoneSuggesterImpl implements TimeZoneSuggester {
                    + ", 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 @@ public class TimeZoneSuggesterImpl implements TimeZoneSuggester {
        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 @@ public class TimeZoneSuggesterImpl implements TimeZoneSuggester {
        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 @@ public class TimeZoneSuggesterImpl implements TimeZoneSuggester {
                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 @@ public class TimeZoneSuggesterImpl implements TimeZoneSuggester {
            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();
    }

    /**
+0 −254
Original line number Diff line number Diff line
/*
 * 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
                + '}';
    }
}
Loading