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

Commit 85c738f6 authored by Wink Saville's avatar Wink Saville Committed by Android (Google) Code Review
Browse files

Merge "If no NITZ information use Country Code to set TimeZone."

parents 672f74bb a27421a3
Loading
Loading
Loading
Loading
+131 −30
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.TimeZone;
import java.util.Date;

@@ -35,18 +37,26 @@ import com.android.internal.util.XmlUtils;
 */
public class TimeUtils {
    /** @hide */ public TimeUtils() {}
    private static final boolean DBG = false;
    private static final String TAG = "TimeUtils";

    /** Cached results of getTineZones */
    private static final Object sLastLockObj = new Object();
    private static ArrayList<TimeZone> sLastZones = null;
    private static String sLastCountry = null;

    /** Cached results of getTimeZonesWithUniqueOffsets */
    private static final Object sLastUniqueLockObj = new Object();
    private static ArrayList<TimeZone> sLastUniqueZoneOffsets = null;
    private static String sLastUniqueCountry = null;


    /**
     * Tries to return a time zone that would have had the specified offset
     * and DST value at the specified moment in the specified country.
     * Returns null if no suitable zone could be found.
     */
    public static TimeZone getTimeZone(int offset, boolean dst, long when, String country) {
        if (country == null) {
            return null;
        }

        TimeZone best = null;

        Resources r = Resources.getSystem();
@@ -58,28 +68,12 @@ public class TimeUtils {
        int currentOffset = current.getOffset(when);
        boolean currentDst = current.inDaylightTime(d);

        try {
            XmlUtils.beginDocument(parser, "timezones");

            while (true) {
                XmlUtils.nextElement(parser);

                String element = parser.getName();
                if (element == null || !(element.equals("timezone"))) {
                    break;
                }

                String code = parser.getAttributeValue(null, "code");

                if (country.equals(code)) {
                    if (parser.next() == XmlPullParser.TEXT) {
                        String maybe = parser.getText();

        for (TimeZone tz : getTimeZones(country)) {
            // If the current time zone is from the right country
            // and meets the other known properties, keep it
            // instead of changing to another one.

                        if (maybe.equals(currentName)) {
            if (tz.getID().equals(currentName)) {
                if (currentOffset == offset && currentDst == dst) {
                    return current;
                }
@@ -91,25 +85,132 @@ public class TimeUtils {
            // haven't encountered the current time zone yet.)

            if (best == null) {
                            TimeZone tz = TimeZone.getTimeZone(maybe);

                if (tz.getOffset(when) == offset &&
                    tz.inDaylightTime(d) == dst) {
                    best = tz;
                }
            }
        }

        return best;
    }

    /**
     * Return list of unique time zones for the country. Do not modify
     *
     * @param country to find
     * @return list of unique time zones, maybe empty but never null. Do not modify.
     * @hide
     */
    public static ArrayList<TimeZone> getTimeZonesWithUniqueOffsets(String country) {
        synchronized(sLastUniqueLockObj) {
            if ((country != null) && country.equals(sLastUniqueCountry)) {
                if (DBG) {
                    Log.d(TAG, "getTimeZonesWithUniqueOffsets(" +
                            country + "): return cached version");
                }
                return sLastUniqueZoneOffsets;
            }
        }

        Collection<TimeZone> zones = getTimeZones(country);
        ArrayList<TimeZone> uniqueTimeZones = new ArrayList<TimeZone>();
        for (TimeZone zone : zones) {
            // See if we already have this offset,
            // Using slow but space efficient and these are small.
            boolean found = false;
            for (int i = 0; i < uniqueTimeZones.size(); i++) {
                if (uniqueTimeZones.get(i).getRawOffset() == zone.getRawOffset()) {
                    found = true;
                    break;
                }
            }
            if (found == false) {
                if (DBG) {
                    Log.d(TAG, "getTimeZonesWithUniqueOffsets: add unique offset=" +
                            zone.getRawOffset() + " zone.getID=" + zone.getID());
                }
                uniqueTimeZones.add(zone);
            }
        }

        synchronized(sLastUniqueLockObj) {
            // Cache the last result
            sLastUniqueZoneOffsets = uniqueTimeZones;
            sLastUniqueCountry = country;

            return sLastUniqueZoneOffsets;
        }
    }

    /**
     * Returns the time zones for the country, which is the code
     * attribute of the timezone element in time_zones_by_country.xml. Do not modify.
     *
     * @param country is a two character country code.
     * @return TimeZone list, maybe empty but never null. Do not modify.
     * @hide
     */
    public static ArrayList<TimeZone> getTimeZones(String country) {
        synchronized (sLastLockObj) {
            if ((country != null) && country.equals(sLastCountry)) {
                if (DBG) Log.d(TAG, "getTimeZones(" + country + "): return cached version");
                return sLastZones;
            }
        }

        ArrayList<TimeZone> tzs = new ArrayList<TimeZone>();

        if (country == null) {
            if (DBG) Log.d(TAG, "getTimeZones(null): return empty list");
            return tzs;
        }

        Resources r = Resources.getSystem();
        XmlResourceParser parser = r.getXml(com.android.internal.R.xml.time_zones_by_country);

        try {
            XmlUtils.beginDocument(parser, "timezones");

            while (true) {
                XmlUtils.nextElement(parser);

                String element = parser.getName();
                if (element == null || !(element.equals("timezone"))) {
                    break;
                }

                String code = parser.getAttributeValue(null, "code");

                if (country.equals(code)) {
                    if (parser.next() == XmlPullParser.TEXT) {
                        String zoneIdString = parser.getText();
                        TimeZone tz = TimeZone.getTimeZone(zoneIdString);
                        if (tz.getID().startsWith("GMT") == false) {
                            // tz.getID doesn't start not "GMT" so its valid
                            tzs.add(tz);
                            if (DBG) {
                                Log.d(TAG, "getTimeZone('" + country + "'): found tz.getID=="
                                    + ((tz != null) ? tz.getID() : "<no tz>"));
                            }
                        }
                    }
                }
            }
        } catch (XmlPullParserException e) {
            Log.e(TAG, "Got exception while getting preferred time zone.", e);
            Log.e(TAG, "Got xml parser exception getTimeZone('" + country + "'): e=", e);
        } catch (IOException e) {
            Log.e(TAG, "Got exception while getting preferred time zone.", e);
            Log.e(TAG, "Got IO exception getTimeZone('" + country + "'): e=", e);
        } finally {
            parser.close();
        }

        return best;
        synchronized(sLastLockObj) {
            // Cache the last result;
            sLastZones = tzs;
            sLastCountry = country;
            return sLastZones;
        }
    }

    /**
+12 −5
Original line number Diff line number Diff line
@@ -2566,6 +2566,12 @@ public final class RIL extends BaseCommands implements CommandsInterface {
                result[0] = ret;
                result[1] = Long.valueOf(nitzReceiveTime);

                boolean ignoreNitz = SystemProperties.getBoolean(
                        TelephonyProperties.PROPERTY_IGNORE_NITZ, false);

                if (ignoreNitz) {
                    if (RILJ_LOGD) riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED");
                } else {
                    if (mNITZTimeRegistrant != null) {

                        mNITZTimeRegistrant
@@ -2574,6 +2580,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
                        // in case NITZ time registrant isnt registered yet
                        mLastNITZTimeInfo = result;
                    }
                }
            break;

            case RIL_UNSOL_SIGNAL_STRENGTH:
+5 −0
Original line number Diff line number Diff line
@@ -182,4 +182,9 @@ public interface TelephonyProperties
     * in commercial configuration.
     */
    static final String PROPERTY_TEST_CSIM = "persist.radio.test-csim";

    /**
     * Ignore RIL_UNSOL_NITZ_TIME_RECEIVED completely, used for debugging/testing.
     */
    static final String PROPERTY_IGNORE_NITZ = "telephony.test.ignore.nitz";
}
+83 −7
Original line number Diff line number Diff line
@@ -59,9 +59,12 @@ import android.util.EventLog;
import android.util.Log;
import android.util.TimeUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.TimeZone;

/**
@@ -112,6 +115,9 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
    private boolean mGotCountryCode = false;
    private ContentResolver cr;

    /** Boolean is true is setTimeFromNITZString was called */
    private boolean mNitzUpdatedTime = false;

    String mSavedTimeZone;
    long mSavedTime;
    long mSavedAtTime;
@@ -698,6 +704,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
                newCellLoc.setStateInvalid();
                setSignalStrengthDefaultValues();
                mGotCountryCode = false;
                mNitzUpdatedTime = false;
                pollStateDone();
            break;

@@ -706,6 +713,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
                newCellLoc.setStateInvalid();
                setSignalStrengthDefaultValues();
                mGotCountryCode = false;
                mNitzUpdatedTime = false;
                pollStateDone();
            break;

@@ -826,6 +834,12 @@ final class GsmServiceStateTracker extends ServiceStateTracker {

        if (hasRegistered) {
            mNetworkAttachedRegistrants.notifyRegistrants();

            if (DBG) {
                log("pollStateDone: registering current mNitzUpdatedTime=" +
                        mNitzUpdatedTime + " changing to false");
            }
            mNitzUpdatedTime = false;
        }

        if (hasChanged) {
@@ -840,28 +854,71 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
            phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric);

            if (operatorNumeric == null) {
                if (DBG) {
                    log("pollStateDone: operatorNumeric is null:" +
                            " clear PROPERTY_OPERATOR_ISO_COUNTRY");
                }
                phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
                mGotCountryCode = false;
                mNitzUpdatedTime = false;
            } else {
                String iso = "";
                String mcc = operatorNumeric.substring(0, 3);
                try{
                    iso = MccTable.countryCodeForMcc(Integer.parseInt(
                            operatorNumeric.substring(0,3)));
                    iso = MccTable.countryCodeForMcc(Integer.parseInt(mcc));
                } catch ( NumberFormatException ex){
                    loge("countryCodeForMcc error" + ex);
                    loge("pollStateDone: countryCodeForMcc error" + ex);
                } catch ( StringIndexOutOfBoundsException ex) {
                    loge("countryCodeForMcc error" + ex);
                    loge("pollStateDone: countryCodeForMcc error" + ex);
                }
                if (DBG) {
                    log("pollStateDone: operatorNumeric=" + operatorNumeric +
                            " mcc=" + mcc + " iso=" + iso);
                }

                phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, iso);
                mGotCountryCode = true;

                if (mNeedFixZone) {
                TimeZone zone = null;

                if (!mNitzUpdatedTime && !mcc.equals("000") && !TextUtils.isEmpty(iso) &&
                        getAutoTimeZone()) {

                    // Test both paths if ignore nitz is true
                    boolean testOneUniqueOffsetPath = SystemProperties.getBoolean(
                                TelephonyProperties.PROPERTY_IGNORE_NITZ, false) &&
                                    ((SystemClock.uptimeMillis() & 1) == 0);

                    ArrayList<TimeZone> uniqueZones = TimeUtils.getTimeZonesWithUniqueOffsets(iso);
                    if ((uniqueZones.size() == 1) || testOneUniqueOffsetPath) {
                        zone = uniqueZones.get(0);
                        if (DBG) {
                           log("pollStateDone: no nitz but one TZ for iso=" + iso +
                                   " with zone.getID=" + zone.getID() +
                                   " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath);
                        }
                        setAndBroadcastNetworkSetTimeZone(zone.getID());
                    } else {
                        if (DBG) {
                            log("pollStateDone: there are " + uniqueZones.size() +
                                " unique offsets for iso='" + iso +
                                " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath +
                                "', do nothing");
                        }
                    }
                }

                if (mNeedFixZone) {
                    // If the offset is (0, false) and the timezone property
                    // is set, use the timezone property rather than
                    // GMT.
                    String zoneName = SystemProperties.get(TIMEZONE_PROPERTY);
                    if (DBG) {
                        log("pollStateDone: mNeedFixZone==true zoneName='" + zoneName +
                            "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst +
                            " iso='" + iso +
                            "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, iso));
                    }
                    if ((mZoneOffset == 0) && (mZoneDst == false) &&
                        (zoneName != null) && (zoneName.length() > 0) &&
                        (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)) {
@@ -876,22 +933,36 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
                            // Adjust the saved NITZ time to account for tzOffset.
                            mSavedTime = mSavedTime - tzOffset;
                        }
                        if (DBG) log("pollStateDone: using default TimeZone");
                    } else if (iso.equals("")){
                        // Country code not found.  This is likely a test network.
                        // Get a TimeZone based only on the NITZ parameters (best guess).
                        zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime);
                        if (DBG) log("pollStateDone: using NITZ TimeZone");
                    } else {
                        zone = TimeUtils.getTimeZone(mZoneOffset,
                            mZoneDst, mZoneTime, iso);
                        zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, iso);
                        if (DBG) log("pollStateDone: using getTimeZone(off, dst, time, iso)");
                    }

                    mNeedFixZone = false;

                    if (zone != null) {
                        log("pollStateDone: zone != null zone.getID=" + zone.getID());
                        if (getAutoTimeZone()) {
                            setAndBroadcastNetworkSetTimeZone(zone.getID());
                        }
                        saveNitzTimeZone(zone.getID());
                    } else {
                        log("pollStateDone: zone == null");
                    }
                } else {
                    if (DBG) {
                        String zoneName = SystemProperties.get(TIMEZONE_PROPERTY);
                        zone = TimeZone.getDefault();
                        log("pollStateDone: mNeedFixZone==false zoneName='" + zoneName +
                                "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst +
                                " iso='" + iso +
                                "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, iso));
                    }
                }
            }
@@ -1440,6 +1511,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
                    long end = SystemClock.elapsedRealtime();
                    log("NITZ: end=" + end + " dur=" + (end - start));
                }
                mNitzUpdatedTime = true;
            } finally {
                mWakeLock.release();
            }
@@ -1489,6 +1561,10 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
        intent.putExtra("time-zone", zoneId);
        phone.getContext().sendStickyBroadcast(intent);
        if (DBG) {
            log("setAndBroadcastNetworkSetTimeZone: call alarm.setTimeZone and broadcast zoneId=" +
                zoneId);
        }
    }

    /**