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

Commit 4a2167e6 authored by Neil Fuller's avatar Neil Fuller Committed by Gerrit Code Review
Browse files

Merge "Move time zone detection logic to system server"

parents bb1a5b4e 3464b9c7
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.internal.telephony.nitz;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.timedetector.PhoneTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.app.timezonedetector.PhoneTimeZoneSuggestion;
import android.content.Context;
import android.content.Context;
import android.telephony.Rlog;
import android.telephony.Rlog;
import android.util.TimestampedValue;
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.NitzStateMachine;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.TimeZoneLookupHelper;
import com.android.internal.telephony.TimeZoneLookupHelper;
import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.IndentingPrintWriter;


import java.io.FileDescriptor;
import java.io.FileDescriptor;
@@ -287,6 +287,7 @@ public final class NewNitzStateMachineImpl implements NitzStateMachine {
            PhoneTimeZoneSuggestion suggestion =
            PhoneTimeZoneSuggestion suggestion =
                    mTimeZoneSuggester.getTimeZoneSuggestion(mPhoneId, countryIsoCode, nitzSignal);
                    mTimeZoneSuggester.getTimeZoneSuggestion(mPhoneId, countryIsoCode, nitzSignal);
            suggestion.addDebugInfo("Detection reason=" + reason);
            suggestion.addDebugInfo("Detection reason=" + reason);

            if (DBG) {
            if (DBG) {
                Rlog.d(LOG_TAG, "doTimeZoneDetection: countryIsoCode=" + countryIsoCode
                Rlog.d(LOG_TAG, "doTimeZoneDetection: countryIsoCode=" + countryIsoCode
                        + ", nitzSignal=" + nitzSignal + ", suggestion=" + suggestion
                        + ", nitzSignal=" + nitzSignal + ", suggestion=" + suggestion
+1 −1
Original line number Original line Diff line number Diff line
@@ -19,8 +19,8 @@ package com.android.internal.telephony.nitz;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.app.timedetector.PhoneTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.app.timedetector.TimeDetector;
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 com.android.internal.util.IndentingPrintWriter;


import java.io.PrintWriter;
import java.io.PrintWriter;
+5 −8
Original line number Original line Diff line number Diff line
@@ -20,14 +20,14 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.timedetector.PhoneTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.app.timedetector.TimeDetector;
import android.app.timedetector.TimeDetector;
import android.app.timezonedetector.PhoneTimeZoneSuggestion;
import android.app.timezonedetector.TimeZoneDetector;
import android.content.Context;
import android.content.Context;
import android.util.LocalLog;
import android.util.LocalLog;
import android.util.TimestampedValue;
import android.util.TimestampedValue;


import com.android.internal.telephony.Phone;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.metrics.TelephonyMetrics;
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 com.android.internal.util.IndentingPrintWriter;


import java.io.PrintWriter;
import java.io.PrintWriter;
@@ -40,7 +40,7 @@ public final class NewTimeServiceHelperImpl implements NewTimeServiceHelper {


    private final int mPhoneId;
    private final int mPhoneId;
    private final TimeDetector mTimeDetector;
    private final TimeDetector mTimeDetector;
    private final TimeZoneDetectionService mTimeZoneDetector;
    private final TimeZoneDetector mTimeZoneDetector;


    private final LocalLog mTimeZoneLog = new LocalLog(30);
    private final LocalLog mTimeZoneLog = new LocalLog(30);
    private final LocalLog mTimeLog = new LocalLog(30);
    private final LocalLog mTimeLog = new LocalLog(30);
@@ -57,7 +57,8 @@ public final class NewTimeServiceHelperImpl implements NewTimeServiceHelper {
        mPhoneId = phone.getPhoneId();
        mPhoneId = phone.getPhoneId();
        Context context = Objects.requireNonNull(phone.getContext());
        Context context = Objects.requireNonNull(phone.getContext());
        mTimeDetector = Objects.requireNonNull(context.getSystemService(TimeDetector.class));
        mTimeDetector = Objects.requireNonNull(context.getSystemService(TimeDetector.class));
        mTimeZoneDetector = Objects.requireNonNull(TimeZoneDetectionService.getInstance(context));
        mTimeZoneDetector =
                Objects.requireNonNull(context.getSystemService(TimeZoneDetector.class));
    }
    }


    @Override
    @Override
@@ -110,14 +111,10 @@ public final class NewTimeServiceHelperImpl implements NewTimeServiceHelper {
        mTimeZoneLog.dump(ipw);
        mTimeZoneLog.dump(ipw);
        ipw.decreaseIndent();
        ipw.decreaseIndent();
        ipw.decreaseIndent();
        ipw.decreaseIndent();

        // TODO Remove this line when the service moves to the system server.
        mTimeZoneDetector.dumpLogs(ipw);
    }
    }


    @Override
    @Override
    public void dumpState(PrintWriter pw) {
    public void dumpState(PrintWriter pw) {
        pw.println(" NewTimeServiceHelperImpl.mLastSuggestedTimeZone=" + mLastSuggestedTimeZone);
        pw.println(" NewTimeServiceHelperImpl.mLastSuggestedTimeZone=" + mLastSuggestedTimeZone);
        mTimeZoneDetector.dumpState(pw);
    }
    }
}
}
+70 −60
Original line number Original line Diff line number Diff line
@@ -16,14 +16,11 @@


package com.android.internal.telephony.nitz;
package com.android.internal.telephony.nitz;


import static com.android.internal.telephony.TimeZoneLookupHelper.CountryResult.QUALITY_DEFAULT_BOOSTED;
import static android.app.timezonedetector.PhoneTimeZoneSuggestion.createEmptySuggestion;
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 android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.timezonedetector.PhoneTimeZoneSuggestion;
import android.telephony.Rlog;
import android.telephony.Rlog;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.TimestampedValue;
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;
import com.android.internal.telephony.TimeZoneLookupHelper.CountryResult;
import com.android.internal.telephony.TimeZoneLookupHelper.CountryResult;
import com.android.internal.telephony.nitz.NewNitzStateMachineImpl.TimeZoneSuggester;
import com.android.internal.telephony.nitz.NewNitzStateMachineImpl.TimeZoneSuggester;
import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;


import java.util.Objects;
import java.util.Objects;


@@ -66,11 +62,13 @@ public class TimeZoneSuggesterImpl implements TimeZoneSuggester {
            if (nitzSignal != null) {
            if (nitzSignal != null) {
                NitzData nitzData = nitzSignal.getValue();
                NitzData nitzData = nitzSignal.getValue();
                if (nitzData.getEmulatorHostTimeZone() != null) {
                if (nitzData.getEmulatorHostTimeZone() != null) {
                    overridingSuggestion = new PhoneTimeZoneSuggestion(phoneId);
                    PhoneTimeZoneSuggestion.Builder builder =
                    overridingSuggestion.setZoneId(nitzData.getEmulatorHostTimeZone().getID());
                            new PhoneTimeZoneSuggestion.Builder(phoneId)
                    overridingSuggestion.setMatchType(PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID);
                            .setZoneId(nitzData.getEmulatorHostTimeZone().getID())
                    overridingSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
                            .setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID)
                    overridingSuggestion.addDebugInfo("Emulator time zone override: " + nitzData);
                            .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
                    + ", nitzSignal=" + nitzSignal
                    + ", e=" + e.getMessage();
                    + ", e=" + e.getMessage();
            PhoneTimeZoneSuggestion errorSuggestion = createEmptySuggestion(phoneId, message);
            PhoneTimeZoneSuggestion errorSuggestion = createEmptySuggestion(phoneId, message);
            errorSuggestion.addDebugInfo(message);
            Rlog.w(LOG_TAG, message, e);
            Rlog.w(LOG_TAG, message, e);
            return errorSuggestion;
            return errorSuggestion;
        }
        }
@@ -142,21 +139,25 @@ public class TimeZoneSuggesterImpl implements TimeZoneSuggester {
        Objects.requireNonNull(nitzSignal);
        Objects.requireNonNull(nitzSignal);
        NitzData nitzData = Objects.requireNonNull(nitzSignal.getValue());
        NitzData nitzData = Objects.requireNonNull(nitzSignal.getValue());


        PhoneTimeZoneSuggestion result = new PhoneTimeZoneSuggestion(phoneId);
        PhoneTimeZoneSuggestion.Builder suggestionBuilder =
        result.addDebugInfo("findTimeZoneForTestNetwork: nitzSignal=" + nitzSignal);
                new PhoneTimeZoneSuggestion.Builder(phoneId);
        suggestionBuilder.addDebugInfo("findTimeZoneForTestNetwork: nitzSignal=" + nitzSignal);
        TimeZoneLookupHelper.OffsetResult lookupResult =
        TimeZoneLookupHelper.OffsetResult lookupResult =
                mTimeZoneLookupHelper.lookupByNitz(nitzData);
                mTimeZoneLookupHelper.lookupByNitz(nitzData);
        if (lookupResult == null) {
        if (lookupResult == null) {
            result.addDebugInfo("findTimeZoneForTestNetwork: No zone found");
            suggestionBuilder.addDebugInfo("findTimeZoneForTestNetwork: No zone found");
        } else {
        } else {
            result.setZoneId(lookupResult.getTimeZone().getID());
            suggestionBuilder.setZoneId(lookupResult.getTimeZone().getID());
            result.setMatchType(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY);
            suggestionBuilder.setMatchType(
            int quality = lookupResult.getIsOnlyMatch() ? PhoneTimeZoneSuggestion.SINGLE_ZONE
                    PhoneTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY);
                    : PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
            int quality = lookupResult.getIsOnlyMatch()
            result.setQuality(quality);
                    ? PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE
            result.addDebugInfo("findTimeZoneForTestNetwork: lookupResult=" + lookupResult);
                    : 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(countryIsoCode);
        Objects.requireNonNull(nitzSignal);
        Objects.requireNonNull(nitzSignal);


        PhoneTimeZoneSuggestion suggestion = new PhoneTimeZoneSuggestion(phoneId);
        PhoneTimeZoneSuggestion.Builder suggestionBuilder =
        suggestion.addDebugInfo("findTimeZoneFromCountryAndNitz: countryIsoCode=" + countryIsoCode
                new PhoneTimeZoneSuggestion.Builder(phoneId);
        suggestionBuilder.addDebugInfo("findTimeZoneFromCountryAndNitz:"
                + " countryIsoCode=" + countryIsoCode
                + ", nitzSignal=" + nitzSignal);
                + ", nitzSignal=" + nitzSignal);
        NitzData nitzData = Objects.requireNonNull(nitzSignal.getValue());
        NitzData nitzData = Objects.requireNonNull(nitzSignal.getValue());
        if (isNitzSignalOffsetInfoBogus(countryIsoCode, nitzData)) {
        if (isNitzSignalOffsetInfoBogus(countryIsoCode, nitzData)) {
            suggestion.addDebugInfo("findTimeZoneFromCountryAndNitz: NITZ signal looks bogus");
            suggestionBuilder.addDebugInfo(
            return suggestion;
                    "findTimeZoneFromCountryAndNitz: NITZ signal looks bogus");
            return suggestionBuilder.build();
        }
        }


        // Try to find a match using both country + NITZ signal.
        // Try to find a match using both country + NITZ signal.
        TimeZoneLookupHelper.OffsetResult lookupResult =
        TimeZoneLookupHelper.OffsetResult lookupResult =
                mTimeZoneLookupHelper.lookupByNitzCountry(nitzData, countryIsoCode);
                mTimeZoneLookupHelper.lookupByNitzCountry(nitzData, countryIsoCode);
        if (lookupResult != null) {
        if (lookupResult != null) {
            suggestion.setZoneId(lookupResult.getTimeZone().getID());
            suggestionBuilder.setZoneId(lookupResult.getTimeZone().getID());
            suggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
            suggestionBuilder.setMatchType(
                    PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET);
            int quality = lookupResult.getIsOnlyMatch()
            int quality = lookupResult.getIsOnlyMatch()
                    ? PhoneTimeZoneSuggestion.SINGLE_ZONE
                    ? PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE
                    : PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
                    : PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
            suggestion.setQuality(quality);
            suggestionBuilder.setQuality(quality);
            suggestion.addDebugInfo("findTimeZoneFromCountryAndNitz: lookupResult=" + lookupResult);
            suggestionBuilder.addDebugInfo("findTimeZoneFromCountryAndNitz:"
            return suggestion;
                    + " lookupResult=" + lookupResult);
            return suggestionBuilder.build();
        }
        }


        // The country + offset provided no match, so see if the country by itself would be enough.
        // 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());
                countryIsoCode, nitzData.getCurrentTimeInMillis());
        if (countryResult == null) {
        if (countryResult == null) {
            // Country not recognized.
            // Country not recognized.
            suggestion.addDebugInfo(
            suggestionBuilder.addDebugInfo(
                    "findTimeZoneFromCountryAndNitz: lookupByCountry() country not recognized");
                    "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
        // 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
        // "boosted" (i.e. the country default is considered a good suggestion in most cases) then
        // use it.
        // use it.
        if (countryResult.quality == QUALITY_SINGLE_ZONE
        if (countryResult.quality == CountryResult.QUALITY_SINGLE_ZONE
                || countryResult.quality == QUALITY_DEFAULT_BOOSTED) {
                || countryResult.quality == CountryResult.QUALITY_DEFAULT_BOOSTED) {
            suggestion.setZoneId(countryResult.zoneId);
            suggestionBuilder.setZoneId(countryResult.zoneId);
            suggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
            suggestionBuilder.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
            suggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
            suggestionBuilder.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
            suggestion.addDebugInfo(
            suggestionBuilder.addDebugInfo(
                    "findTimeZoneFromCountryAndNitz: high quality country-only suggestion:"
                    "findTimeZoneFromCountryAndNitz: high quality country-only suggestion:"
                            + " countryResult=" + countryResult);
                            + " countryResult=" + countryResult);
            return suggestion;
            return suggestionBuilder.build();
        }
        }


        // Quality is not high enough to set the zone using country only.
        // Quality is not high enough to set the zone using country only.
        suggestion.addDebugInfo("findTimeZoneFromCountryAndNitz: country-only suggestion quality"
        suggestionBuilder.addDebugInfo("findTimeZoneFromCountryAndNitz: country-only suggestion"
                + " not high enough. countryResult=" + countryResult);
                + " quality not high enough. countryResult=" + countryResult);
        return suggestion;
        return suggestionBuilder.build();
    }
    }


    /**
    /**
@@ -237,35 +243,39 @@ public class TimeZoneSuggesterImpl implements TimeZoneSuggester {
            throw new IllegalArgumentException("countryIsoCode must not be empty");
            throw new IllegalArgumentException("countryIsoCode must not be empty");
        }
        }


        PhoneTimeZoneSuggestion result = new PhoneTimeZoneSuggestion(phoneId);
        PhoneTimeZoneSuggestion.Builder suggestionBuilder =
        result.addDebugInfo("findTimeZoneFromNetworkCountryCode:"
                new PhoneTimeZoneSuggestion.Builder(phoneId);
        suggestionBuilder.addDebugInfo("findTimeZoneFromNetworkCountryCode:"
                + " whenMillis=" + whenMillis + ", countryIsoCode=" + countryIsoCode);
                + " whenMillis=" + whenMillis + ", countryIsoCode=" + countryIsoCode);
        CountryResult lookupResult = mTimeZoneLookupHelper.lookupByCountry(
        CountryResult lookupResult = mTimeZoneLookupHelper.lookupByCountry(
                countryIsoCode, whenMillis);
                countryIsoCode, whenMillis);
        if (lookupResult != null) {
        if (lookupResult != null) {
            result.setZoneId(lookupResult.zoneId);
            suggestionBuilder.setZoneId(lookupResult.zoneId);
            result.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
            suggestionBuilder.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);


            int quality;
            int quality;
            if (lookupResult.quality == QUALITY_SINGLE_ZONE
            if (lookupResult.quality == CountryResult.QUALITY_SINGLE_ZONE
                    || lookupResult.quality == QUALITY_DEFAULT_BOOSTED) {
                    || lookupResult.quality == CountryResult.QUALITY_DEFAULT_BOOSTED) {
                quality = PhoneTimeZoneSuggestion.SINGLE_ZONE;
                quality = PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
            } else if (lookupResult.quality == QUALITY_MULTIPLE_ZONES_SAME_OFFSET) {
            } else if (lookupResult.quality == CountryResult.QUALITY_MULTIPLE_ZONES_SAME_OFFSET) {
                quality = PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
                quality = PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
            } else if (lookupResult.quality == QUALITY_MULTIPLE_ZONES_DIFFERENT_OFFSETS) {
            } else if (lookupResult.quality
                quality = PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
                    == CountryResult.QUALITY_MULTIPLE_ZONES_DIFFERENT_OFFSETS) {
                quality = PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
            } else {
            } else {
                // This should never happen.
                // This should never happen.
                throw new IllegalArgumentException(
                throw new IllegalArgumentException(
                        "lookupResult.quality not recognized: countryIsoCode=" + countryIsoCode
                        "lookupResult.quality not recognized: countryIsoCode=" + countryIsoCode
                                + ", whenMillis=" + whenMillis + ", lookupResult=" + lookupResult);
                                + ", whenMillis=" + whenMillis + ", lookupResult=" + lookupResult);
            }
            }
            result.setQuality(quality);
            suggestionBuilder.setQuality(quality);
            result.addDebugInfo("findTimeZoneFromNetworkCountryCode: lookupResult=" + lookupResult);
            suggestionBuilder.addDebugInfo(
                    "findTimeZoneFromNetworkCountryCode: lookupResult=" + lookupResult);
        } else {
        } else {
            result.addDebugInfo("findTimeZoneFromNetworkCountryCode: Country not recognized?");
            suggestionBuilder.addDebugInfo(
                    "findTimeZoneFromNetworkCountryCode: Country not recognized?");
        }
        }
        return result;
        return suggestionBuilder.build();
    }
    }


    /**
    /**
+0 −254
Original line number Original line 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