Merge "If no NITZ information use Country Code to set TimeZone."
This commit is contained in:
@@ -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,6 +68,107 @@ public class TimeUtils {
|
||||
int currentOffset = current.getOffset(when);
|
||||
boolean currentDst = current.inDaylightTime(d);
|
||||
|
||||
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 (tz.getID().equals(currentName)) {
|
||||
if (currentOffset == offset && currentDst == dst) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, take the first zone from the right
|
||||
// country that has the correct current offset and DST.
|
||||
// (Keep iterating instead of returning in case we
|
||||
// haven't encountered the current time zone yet.)
|
||||
|
||||
if (best == null) {
|
||||
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");
|
||||
|
||||
@@ -73,43 +184,33 @@ public class TimeUtils {
|
||||
|
||||
if (country.equals(code)) {
|
||||
if (parser.next() == XmlPullParser.TEXT) {
|
||||
String maybe = parser.getText();
|
||||
|
||||
// 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 (currentOffset == offset && currentDst == dst) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, take the first zone from the right
|
||||
// country that has the correct current offset and DST.
|
||||
// (Keep iterating instead of returning in case we
|
||||
// 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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2566,13 +2566,20 @@ public final class RIL extends BaseCommands implements CommandsInterface {
|
||||
result[0] = ret;
|
||||
result[1] = Long.valueOf(nitzReceiveTime);
|
||||
|
||||
if (mNITZTimeRegistrant != null) {
|
||||
boolean ignoreNitz = SystemProperties.getBoolean(
|
||||
TelephonyProperties.PROPERTY_IGNORE_NITZ, false);
|
||||
|
||||
mNITZTimeRegistrant
|
||||
.notifyRegistrant(new AsyncResult (null, result, null));
|
||||
if (ignoreNitz) {
|
||||
if (RILJ_LOGD) riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED");
|
||||
} else {
|
||||
// in case NITZ time registrant isnt registered yet
|
||||
mLastNITZTimeInfo = result;
|
||||
if (mNITZTimeRegistrant != null) {
|
||||
|
||||
mNITZTimeRegistrant
|
||||
.notifyRegistrant(new AsyncResult (null, result, null));
|
||||
} else {
|
||||
// in case NITZ time registrant isnt registered yet
|
||||
mLastNITZTimeInfo = result;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
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) {
|
||||
TimeZone zone = null;
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user