GsmServiceStateTracker.java revision b496aacaf6811afb18910dba756f5bc2c83b5fad
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.telephony.gsm; 18 19import android.app.AlarmManager; 20import android.app.Notification; 21import android.app.NotificationManager; 22import android.app.PendingIntent; 23import android.content.BroadcastReceiver; 24import android.content.ContentResolver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.content.res.Resources; 29import android.database.ContentObserver; 30import android.os.AsyncResult; 31import android.os.Build; 32import android.os.Handler; 33import android.os.Message; 34import android.os.PowerManager; 35import android.os.SystemClock; 36import android.os.SystemProperties; 37import android.os.UserHandle; 38import android.provider.Settings; 39import android.provider.Settings.SettingNotFoundException; 40import android.telephony.CellIdentityGsm; 41import android.telephony.CellIdentityLte; 42import android.telephony.CellIdentityWcdma; 43import android.telephony.CellInfo; 44import android.telephony.CellInfoGsm; 45import android.telephony.CellInfoLte; 46import android.telephony.CellInfoWcdma; 47import android.telephony.CellLocation; 48import android.telephony.Rlog; 49import android.telephony.ServiceState; 50import android.telephony.SignalStrength; 51import android.telephony.gsm.GsmCellLocation; 52import android.telephony.TelephonyManager; 53import android.text.TextUtils; 54import android.util.EventLog; 55import android.util.TimeUtils; 56 57import com.android.internal.telephony.CommandException; 58import com.android.internal.telephony.CommandsInterface; 59import com.android.internal.telephony.EventLogTags; 60import com.android.internal.telephony.MccTable; 61import com.android.internal.telephony.PhoneConstants; 62import com.android.internal.telephony.ProxyController; 63import com.android.internal.telephony.Phone; 64import com.android.internal.telephony.PhoneFactory; 65import com.android.internal.telephony.RILConstants; 66import com.android.internal.telephony.RestrictedState; 67import com.android.internal.telephony.ServiceStateTracker; 68import android.telephony.SubscriptionManager; 69import com.android.internal.telephony.TelephonyIntents; 70import com.android.internal.telephony.TelephonyProperties; 71import com.android.internal.telephony.dataconnection.DcTrackerBase; 72import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; 73import com.android.internal.telephony.uicc.IccRecords; 74import com.android.internal.telephony.uicc.SIMRecords; 75import com.android.internal.telephony.uicc.UiccCardApplication; 76import com.android.internal.telephony.uicc.UiccController; 77 78import java.io.FileDescriptor; 79import java.io.PrintWriter; 80import java.util.ArrayList; 81import java.util.Arrays; 82import java.util.Calendar; 83import java.util.Date; 84import java.util.List; 85import java.util.TimeZone; 86 87/** 88 * {@hide} 89 */ 90final class GsmServiceStateTracker extends ServiceStateTracker { 91 static final String LOG_TAG = "GsmSST"; 92 static final boolean VDBG = false; 93 //CAF_MSIM make it private ?? 94 private static final int EVENT_ALL_DATA_DISCONNECTED = 1001; 95 private GSMPhone mPhone; 96 GsmCellLocation mCellLoc; 97 GsmCellLocation mNewCellLoc; 98 int mPreferredNetworkType; 99 100 private int mMaxDataCalls = 1; 101 private int mNewMaxDataCalls = 1; 102 private int mReasonDataDenied = -1; 103 private int mNewReasonDataDenied = -1; 104 105 /** 106 * GSM roaming status solely based on TS 27.007 7.2 CREG. Only used by 107 * handlePollStateResult to store CREG roaming result. 108 */ 109 private boolean mGsmRoaming = false; 110 111 /** 112 * Data roaming status solely based on TS 27.007 10.1.19 CGREG. Only used by 113 * handlePollStateResult to store CGREG roaming result. 114 */ 115 private boolean mDataRoaming = false; 116 117 /** 118 * Mark when service state is in emergency call only mode 119 */ 120 private boolean mEmergencyOnly = false; 121 122 /** 123 * Sometimes we get the NITZ time before we know what country we 124 * are in. Keep the time zone information from the NITZ string so 125 * we can fix the time zone once know the country. 126 */ 127 private boolean mNeedFixZoneAfterNitz = false; 128 private int mZoneOffset; 129 private boolean mZoneDst; 130 private long mZoneTime; 131 private boolean mGotCountryCode = false; 132 private ContentResolver mCr; 133 134 /** Boolean is true is setTimeFromNITZString was called */ 135 private boolean mNitzUpdatedTime = false; 136 137 String mSavedTimeZone; 138 long mSavedTime; 139 long mSavedAtTime; 140 141 /** Started the recheck process after finding gprs should registered but not. */ 142 private boolean mStartedGprsRegCheck = false; 143 144 /** Already sent the event-log for no gprs register. */ 145 private boolean mReportedGprsNoReg = false; 146 147 /** 148 * The Notification object given to the NotificationManager. 149 */ 150 private Notification mNotification; 151 152 /** Wake lock used while setting time of day. */ 153 private PowerManager.WakeLock mWakeLock; 154 private static final String WAKELOCK_TAG = "ServiceStateTracker"; 155 156 /** Keep track of SPN display rules, so we only broadcast intent if something changes. */ 157 private String mCurSpn = null; 158 private String mCurPlmn = null; 159 private boolean mCurShowPlmn = false; 160 private boolean mCurShowSpn = false; 161 162 /** Notification type. */ 163 static final int PS_ENABLED = 1001; // Access Control blocks data service 164 static final int PS_DISABLED = 1002; // Access Control enables data service 165 static final int CS_ENABLED = 1003; // Access Control blocks all voice/sms service 166 static final int CS_DISABLED = 1004; // Access Control enables all voice/sms service 167 static final int CS_NORMAL_ENABLED = 1005; // Access Control blocks normal voice/sms service 168 static final int CS_EMERGENCY_ENABLED = 1006; // Access Control blocks emergency call service 169 170 /** Notification id. */ 171 static final int PS_NOTIFICATION = 888; // Id to update and cancel PS restricted 172 static final int CS_NOTIFICATION = 999; // Id to update and cancel CS restricted 173 174 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 175 @Override 176 public void onReceive(Context context, Intent intent) { 177 if (!mPhone.mIsTheCurrentActivePhone) { 178 Rlog.e(LOG_TAG, "Received Intent " + intent + 179 " while being destroyed. Ignoring."); 180 return; 181 } 182 183 if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) { 184 // update emergency string whenever locale changed 185 updateSpnDisplay(); 186 } else if (intent.getAction().equals(ACTION_RADIO_OFF)) { 187 mAlarmSwitch = false; 188 DcTrackerBase dcTracker = mPhone.mDcTracker; 189 powerOffRadioSafely(dcTracker); 190 } 191 } 192 }; 193 194 private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) { 195 @Override 196 public void onChange(boolean selfChange) { 197 Rlog.i("GsmServiceStateTracker", "Auto time state changed"); 198 revertToNitzTime(); 199 } 200 }; 201 202 private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) { 203 @Override 204 public void onChange(boolean selfChange) { 205 Rlog.i("GsmServiceStateTracker", "Auto time zone state changed"); 206 revertToNitzTimeZone(); 207 } 208 }; 209 210 public GsmServiceStateTracker(GSMPhone phone) { 211 super(phone, phone.mCi, new CellInfoGsm()); 212 213 mPhone = phone; 214 mCellLoc = new GsmCellLocation(); 215 mNewCellLoc = new GsmCellLocation(); 216 217 PowerManager powerManager = 218 (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE); 219 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); 220 221 mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); 222 mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); 223 224 mCi.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null); 225 mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null); 226 mCi.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null); 227 228 // system setting property AIRPLANE_MODE_ON is set in Settings. 229 int airplaneMode = Settings.Global.getInt( 230 phone.getContext().getContentResolver(), 231 Settings.Global.AIRPLANE_MODE_ON, 0); 232 mDesiredPowerState = ! (airplaneMode > 0); 233 234 mCr = phone.getContext().getContentResolver(); 235 mCr.registerContentObserver( 236 Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true, 237 mAutoTimeObserver); 238 mCr.registerContentObserver( 239 Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, 240 mAutoTimeZoneObserver); 241 242 setSignalStrengthDefaultValues(); 243 244 // Monitor locale change 245 IntentFilter filter = new IntentFilter(); 246 filter.addAction(Intent.ACTION_LOCALE_CHANGED); 247 phone.getContext().registerReceiver(mIntentReceiver, filter); 248 249 filter = new IntentFilter(); 250 Context context = phone.getContext(); 251 filter.addAction(ACTION_RADIO_OFF); 252 context.registerReceiver(mIntentReceiver, filter); 253 254 // Gsm doesn't support OTASP so its not needed 255 phone.notifyOtaspChanged(OTASP_NOT_NEEDED); 256 } 257 258 @Override 259 public void dispose() { 260 checkCorrectThread(); 261 log("ServiceStateTracker dispose"); 262 263 // Unregister for all events. 264 mCi.unregisterForAvailable(this); 265 mCi.unregisterForRadioStateChanged(this); 266 mCi.unregisterForVoiceNetworkStateChanged(this); 267 if (mUiccApplcation != null) {mUiccApplcation.unregisterForReady(this);} 268 if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);} 269 mCi.unSetOnRestrictedStateChanged(this); 270 mCi.unSetOnNITZTime(this); 271 mCr.unregisterContentObserver(mAutoTimeObserver); 272 mCr.unregisterContentObserver(mAutoTimeZoneObserver); 273 mPhone.getContext().unregisterReceiver(mIntentReceiver); 274 super.dispose(); 275 } 276 277 @Override 278 protected void finalize() { 279 if(DBG) log("finalize"); 280 } 281 282 @Override 283 protected Phone getPhone() { 284 return mPhone; 285 } 286 287 @Override 288 public void handleMessage (Message msg) { 289 AsyncResult ar; 290 int[] ints; 291 String[] strings; 292 Message message; 293 294 if (!mPhone.mIsTheCurrentActivePhone) { 295 Rlog.e(LOG_TAG, "Received message " + msg + 296 "[" + msg.what + "] while being destroyed. Ignoring."); 297 return; 298 } 299 switch (msg.what) { 300 case EVENT_RADIO_AVAILABLE: 301 //this is unnecessary 302 //setPowerStateToDesired(); 303 break; 304 305 case EVENT_SIM_READY: 306 // Set the network type, in case the radio does not restore it. 307 int networkType = PhoneFactory.calculatePreferredNetworkType(mPhone.getContext()); 308 mCi.setPreferredNetworkType(networkType, null); 309 310 boolean skipRestoringSelection = mPhone.getContext().getResources().getBoolean( 311 com.android.internal.R.bool.skip_restoring_network_selection); 312 313 if (!skipRestoringSelection) { 314 // restore the previous network selection. 315 mPhone.restoreSavedNetworkSelection(null); 316 } 317 pollState(); 318 // Signal strength polling stops when radio is off 319 queueNextSignalStrengthPoll(); 320 break; 321 322 case EVENT_RADIO_STATE_CHANGED: 323 // This will do nothing in the radio not 324 // available case 325 setPowerStateToDesired(); 326 pollState(); 327 break; 328 329 case EVENT_NETWORK_STATE_CHANGED: 330 pollState(); 331 break; 332 333 case EVENT_GET_SIGNAL_STRENGTH: 334 // This callback is called when signal strength is polled 335 // all by itself 336 337 if (!(mCi.getRadioState().isOn())) { 338 // Polling will continue when radio turns back on 339 return; 340 } 341 ar = (AsyncResult) msg.obj; 342 onSignalStrengthResult(ar, true); 343 queueNextSignalStrengthPoll(); 344 345 break; 346 347 case EVENT_GET_LOC_DONE: 348 ar = (AsyncResult) msg.obj; 349 350 if (ar.exception == null) { 351 String states[] = (String[])ar.result; 352 int lac = -1; 353 int cid = -1; 354 if (states.length >= 3) { 355 try { 356 if (states[1] != null && states[1].length() > 0) { 357 lac = Integer.parseInt(states[1], 16); 358 } 359 if (states[2] != null && states[2].length() > 0) { 360 cid = Integer.parseInt(states[2], 16); 361 } 362 } catch (NumberFormatException ex) { 363 Rlog.w(LOG_TAG, "error parsing location: " + ex); 364 } 365 } 366 mCellLoc.setLacAndCid(lac, cid); 367 mPhone.notifyLocationChanged(); 368 } 369 370 // Release any temporary cell lock, which could have been 371 // acquired to allow a single-shot location update. 372 disableSingleLocationUpdate(); 373 break; 374 375 case EVENT_POLL_STATE_REGISTRATION: 376 case EVENT_POLL_STATE_GPRS: 377 case EVENT_POLL_STATE_OPERATOR: 378 case EVENT_POLL_STATE_NETWORK_SELECTION_MODE: 379 ar = (AsyncResult) msg.obj; 380 381 handlePollStateResult(msg.what, ar); 382 break; 383 384 case EVENT_POLL_SIGNAL_STRENGTH: 385 // Just poll signal strength...not part of pollState() 386 387 mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH)); 388 break; 389 390 case EVENT_NITZ_TIME: 391 ar = (AsyncResult) msg.obj; 392 393 String nitzString = (String)((Object[])ar.result)[0]; 394 long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue(); 395 396 setTimeFromNITZString(nitzString, nitzReceiveTime); 397 break; 398 399 case EVENT_SIGNAL_STRENGTH_UPDATE: 400 // This is a notification from 401 // CommandsInterface.setOnSignalStrengthUpdate 402 403 ar = (AsyncResult) msg.obj; 404 405 // The radio is telling us about signal strength changes 406 // we don't have to ask it 407 mDontPollSignalStrength = true; 408 409 onSignalStrengthResult(ar, true); 410 break; 411 412 case EVENT_SIM_RECORDS_LOADED: 413 log("EVENT_SIM_RECORDS_LOADED: what=" + msg.what); 414 415 updatePhoneObject(); 416 updateSpnDisplay(); 417 break; 418 419 case EVENT_LOCATION_UPDATES_ENABLED: 420 ar = (AsyncResult) msg.obj; 421 422 if (ar.exception == null) { 423 mCi.getVoiceRegistrationState(obtainMessage(EVENT_GET_LOC_DONE, null)); 424 } 425 break; 426 427 case EVENT_SET_PREFERRED_NETWORK_TYPE: 428 ar = (AsyncResult) msg.obj; 429 // Don't care the result, only use for dereg network (COPS=2) 430 message = obtainMessage(EVENT_RESET_PREFERRED_NETWORK_TYPE, ar.userObj); 431 mCi.setPreferredNetworkType(mPreferredNetworkType, message); 432 break; 433 434 case EVENT_RESET_PREFERRED_NETWORK_TYPE: 435 ar = (AsyncResult) msg.obj; 436 if (ar.userObj != null) { 437 AsyncResult.forMessage(((Message) ar.userObj)).exception 438 = ar.exception; 439 ((Message) ar.userObj).sendToTarget(); 440 } 441 break; 442 443 case EVENT_GET_PREFERRED_NETWORK_TYPE: 444 ar = (AsyncResult) msg.obj; 445 446 if (ar.exception == null) { 447 mPreferredNetworkType = ((int[])ar.result)[0]; 448 } else { 449 mPreferredNetworkType = RILConstants.NETWORK_MODE_GLOBAL; 450 } 451 452 message = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE, ar.userObj); 453 int toggledNetworkType = RILConstants.NETWORK_MODE_GLOBAL; 454 455 mCi.setPreferredNetworkType(toggledNetworkType, message); 456 break; 457 458 case EVENT_CHECK_REPORT_GPRS: 459 if (mSS != null && !isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) { 460 461 // Can't register data service while voice service is ok 462 // i.e. CREG is ok while CGREG is not 463 // possible a network or baseband side error 464 GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation()); 465 EventLog.writeEvent(EventLogTags.DATA_NETWORK_REGISTRATION_FAIL, 466 mSS.getOperatorNumeric(), loc != null ? loc.getCid() : -1); 467 mReportedGprsNoReg = true; 468 } 469 mStartedGprsRegCheck = false; 470 break; 471 472 case EVENT_RESTRICTED_STATE_CHANGED: 473 // This is a notification from 474 // CommandsInterface.setOnRestrictedStateChanged 475 476 if (DBG) log("EVENT_RESTRICTED_STATE_CHANGED"); 477 478 ar = (AsyncResult) msg.obj; 479 480 onRestrictedStateChanged(ar); 481 break; 482 483 case EVENT_ALL_DATA_DISCONNECTED: 484 long dds = SubscriptionManager.getDefaultDataSubId(); 485 ProxyController.getInstance().unregisterForAllDataDisconnected(dds, this); 486 synchronized(this) { 487 if (mPendingRadioPowerOffAfterDataOff) { 488 if (DBG) log("EVENT_ALL_DATA_DISCONNECTED, turn radio off now."); 489 hangupAndPowerOff(); 490 mPendingRadioPowerOffAfterDataOff = false; 491 } else { 492 log("EVENT_ALL_DATA_DISCONNECTED is stale"); 493 } 494 } 495 break; 496 497 case EVENT_CHANGE_IMS_STATE: 498 if (DBG) log("EVENT_CHANGE_IMS_STATE:"); 499 500 setPowerStateToDesired(); 501 break; 502 503 default: 504 super.handleMessage(msg); 505 break; 506 } 507 } 508 509 @Override 510 protected void setPowerStateToDesired() { 511 512 if (DBG) { 513 log("mDeviceShuttingDown = " + mDeviceShuttingDown); 514 log("mDesiredPowerState = " + mDesiredPowerState); 515 log("getRadioState = " + mCi.getRadioState()); 516 log("mPowerOffDelayNeed = " + mPowerOffDelayNeed); 517 log("mAlarmSwitch = " + mAlarmSwitch); 518 } 519 520 if (mAlarmSwitch) { 521 if(DBG) log("mAlarmSwitch == true"); 522 Context context = mPhone.getContext(); 523 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 524 am.cancel(mRadioOffIntent); 525 mAlarmSwitch = false; 526 } 527 528 // If we want it on and it's off, turn it on 529 if (mDesiredPowerState 530 && mCi.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) { 531 mCi.setRadioPower(true, null); 532 } else if (!mDesiredPowerState && mCi.getRadioState().isOn()) { 533 // If it's on and available and we want it off gracefully 534 if (mPowerOffDelayNeed) { 535 if (mImsRegistrationOnOff && !mAlarmSwitch) { 536 if(DBG) log("mImsRegistrationOnOff == true"); 537 Context context = mPhone.getContext(); 538 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 539 540 Intent intent = new Intent(ACTION_RADIO_OFF); 541 mRadioOffIntent = PendingIntent.getBroadcast(context, 0, intent, 0); 542 543 mAlarmSwitch = true; 544 if (DBG) log("Alarm setting"); 545 am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 546 SystemClock.elapsedRealtime() + 3000, mRadioOffIntent); 547 } else { 548 DcTrackerBase dcTracker = mPhone.mDcTracker; 549 powerOffRadioSafely(dcTracker); 550 } 551 } else { 552 DcTrackerBase dcTracker = mPhone.mDcTracker; 553 powerOffRadioSafely(dcTracker); 554 } 555 } else if (mDeviceShuttingDown && mCi.getRadioState().isAvailable()) { 556 mCi.requestShutdown(null); 557 } 558 } 559 560 @Override 561 protected void hangupAndPowerOff() { 562 // hang up all active voice calls 563 if (mPhone.isInCall()) { 564 mPhone.mCT.mRingingCall.hangupIfAlive(); 565 mPhone.mCT.mBackgroundCall.hangupIfAlive(); 566 mPhone.mCT.mForegroundCall.hangupIfAlive(); 567 } 568 569 mCi.setRadioPower(false, null); 570 } 571 572 @Override 573 protected void updateSpnDisplay() { 574 // The values of plmn/showPlmn change in different scenarios. 575 // 1) No service but emergency call allowed -> expected 576 // to show "Emergency call only" 577 // EXTRA_SHOW_PLMN = true 578 // EXTRA_PLMN = "Emergency call only" 579 580 // 2) No service at all --> expected to show "No service" 581 // EXTRA_SHOW_PLMN = true 582 // EXTRA_PLMN = "No service" 583 584 // 3) Normal operation in either home or roaming service 585 // EXTRA_SHOW_PLMN = depending on IccRecords rule 586 // EXTRA_PLMN = plmn 587 588 // 4) No service due to power off, aka airplane mode 589 // EXTRA_SHOW_PLMN = false 590 // EXTRA_PLMN = null 591 592 IccRecords iccRecords = mIccRecords; 593 String plmn = null; 594 boolean showPlmn = false; 595 int rule = (iccRecords != null) ? iccRecords.getDisplayRule(mSS.getOperatorNumeric()) : 0; 596 if (mSS.getVoiceRegState() == ServiceState.STATE_OUT_OF_SERVICE 597 || mSS.getVoiceRegState() == ServiceState.STATE_EMERGENCY_ONLY) { 598 showPlmn = true; 599 if (mEmergencyOnly) { 600 // No service but emergency call allowed 601 plmn = Resources.getSystem(). 602 getText(com.android.internal.R.string.emergency_calls_only).toString(); 603 } else { 604 // No service at all 605 plmn = Resources.getSystem(). 606 getText(com.android.internal.R.string.lockscreen_carrier_default).toString(); 607 } 608 if (DBG) log("updateSpnDisplay: radio is on but out " + 609 "of service, set plmn='" + plmn + "'"); 610 } else if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) { 611 // In either home or roaming service 612 plmn = mSS.getOperatorAlphaLong(); 613 showPlmn = !TextUtils.isEmpty(plmn) && 614 ((rule & SIMRecords.SPN_RULE_SHOW_PLMN) 615 == SIMRecords.SPN_RULE_SHOW_PLMN); 616 } else { 617 // Power off state, such as airplane mode 618 if (DBG) log("updateSpnDisplay: radio is off w/ showPlmn=" 619 + showPlmn + " plmn=" + plmn); 620 } 621 622 // The value of spn/showSpn are same in different scenarios. 623 // EXTRA_SHOW_SPN = depending on IccRecords rule 624 // EXTRA_SPN = spn 625 String spn = (iccRecords != null) ? iccRecords.getServiceProviderName() : ""; 626 boolean showSpn = !TextUtils.isEmpty(spn) 627 && ((rule & SIMRecords.SPN_RULE_SHOW_SPN) 628 == SIMRecords.SPN_RULE_SHOW_SPN); 629 630 // Update SPN_STRINGS_UPDATED_ACTION IFF any value changes 631 if (showPlmn != mCurShowPlmn 632 || showSpn != mCurShowSpn 633 || !TextUtils.equals(spn, mCurSpn) 634 || !TextUtils.equals(plmn, mCurPlmn)) { 635 if (DBG) { 636 log(String.format("updateSpnDisplay: changed" + 637 " sending intent rule=" + rule + 638 " showPlmn='%b' plmn='%s' showSpn='%b' spn='%s'", 639 showPlmn, plmn, showSpn, spn)); 640 } 641 Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); 642 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 643 intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, showSpn); 644 intent.putExtra(TelephonyIntents.EXTRA_SPN, spn); 645 intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn); 646 intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn); 647 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); 648 mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); 649 } 650 651 mCurShowSpn = showSpn; 652 mCurShowPlmn = showPlmn; 653 mCurSpn = spn; 654 mCurPlmn = plmn; 655 } 656 657 /** 658 * Handle the result of one of the pollState()-related requests 659 */ 660 @Override 661 protected void handlePollStateResult (int what, AsyncResult ar) { 662 int ints[]; 663 String states[]; 664 665 // Ignore stale requests from last poll 666 if (ar.userObj != mPollingContext) return; 667 668 if (ar.exception != null) { 669 CommandException.Error err=null; 670 671 if (ar.exception instanceof CommandException) { 672 err = ((CommandException)(ar.exception)).getCommandError(); 673 } 674 675 if (err == CommandException.Error.RADIO_NOT_AVAILABLE) { 676 // Radio has crashed or turned off 677 cancelPollState(); 678 return; 679 } 680 681 if (!mCi.getRadioState().isOn()) { 682 // Radio has crashed or turned off 683 cancelPollState(); 684 return; 685 } 686 687 if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) { 688 loge("RIL implementation has returned an error where it must succeed" + 689 ar.exception); 690 } 691 } else try { 692 switch (what) { 693 case EVENT_POLL_STATE_REGISTRATION: { 694 states = (String[])ar.result; 695 int lac = -1; 696 int cid = -1; 697 int type = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; 698 int regState = ServiceState.RIL_REG_STATE_UNKNOWN; 699 int reasonRegStateDenied = -1; 700 int psc = -1; 701 if (states.length > 0) { 702 try { 703 regState = Integer.parseInt(states[0]); 704 if (states.length >= 3) { 705 if (states[1] != null && states[1].length() > 0) { 706 lac = Integer.parseInt(states[1], 16); 707 } 708 if (states[2] != null && states[2].length() > 0) { 709 cid = Integer.parseInt(states[2], 16); 710 } 711 712 // states[3] (if present) is the current radio technology 713 if (states.length >= 4 && states[3] != null) { 714 type = Integer.parseInt(states[3]); 715 } 716 } 717 if (states.length > 14) { 718 if (states[14] != null && states[14].length() > 0) { 719 psc = Integer.parseInt(states[14], 16); 720 } 721 } 722 } catch (NumberFormatException ex) { 723 loge("error parsing RegistrationState: " + ex); 724 } 725 } 726 727 mGsmRoaming = regCodeIsRoaming(regState); 728 mNewSS.setState(regCodeToServiceState(regState)); 729 mNewSS.setRilVoiceRadioTechnology(type); 730 731 boolean isVoiceCapable = mPhoneBase.getContext().getResources() 732 .getBoolean(com.android.internal.R.bool.config_voice_capable); 733 if ((regState == ServiceState.RIL_REG_STATE_DENIED_EMERGENCY_CALL_ENABLED 734 || regState == ServiceState.RIL_REG_STATE_NOT_REG_EMERGENCY_CALL_ENABLED 735 || regState == ServiceState.RIL_REG_STATE_SEARCHING_EMERGENCY_CALL_ENABLED 736 || regState == ServiceState.RIL_REG_STATE_UNKNOWN_EMERGENCY_CALL_ENABLED) 737 && isVoiceCapable) { 738 mEmergencyOnly = true; 739 } else { 740 mEmergencyOnly = false; 741 } 742 743 // LAC and CID are -1 if not avail 744 mNewCellLoc.setLacAndCid(lac, cid); 745 mNewCellLoc.setPsc(psc); 746 break; 747 } 748 749 case EVENT_POLL_STATE_GPRS: { 750 states = (String[])ar.result; 751 752 int type = 0; 753 int regState = ServiceState.RIL_REG_STATE_UNKNOWN; 754 mNewReasonDataDenied = -1; 755 mNewMaxDataCalls = 1; 756 if (states.length > 0) { 757 try { 758 regState = Integer.parseInt(states[0]); 759 760 // states[3] (if present) is the current radio technology 761 if (states.length >= 4 && states[3] != null) { 762 type = Integer.parseInt(states[3]); 763 } 764 if ((states.length >= 5 ) && 765 (regState == ServiceState.RIL_REG_STATE_DENIED)) { 766 mNewReasonDataDenied = Integer.parseInt(states[4]); 767 } 768 if (states.length >= 6) { 769 mNewMaxDataCalls = Integer.parseInt(states[5]); 770 } 771 } catch (NumberFormatException ex) { 772 loge("error parsing GprsRegistrationState: " + ex); 773 } 774 } 775 int dataRegState = regCodeToServiceState(regState); 776 mNewSS.setDataRegState(dataRegState); 777 mDataRoaming = regCodeIsRoaming(regState); 778 mNewSS.setRilDataRadioTechnology(type); 779 if (DBG) { 780 log("handlPollStateResultMessage: GsmSST setDataRegState=" + dataRegState 781 + " regState=" + regState 782 + " dataRadioTechnology=" + type); 783 } 784 break; 785 } 786 787 case EVENT_POLL_STATE_OPERATOR: { 788 String opNames[] = (String[])ar.result; 789 790 if (opNames != null && opNames.length >= 3) { 791 String brandOverride = mUiccController.getUiccCard() != null ? 792 mUiccController.getUiccCard().getOperatorBrandOverride() : null; 793 if (brandOverride != null) { 794 mNewSS.setOperatorName(brandOverride, brandOverride, opNames[2]); 795 } else { 796 mNewSS.setOperatorName(opNames[0], opNames[1], opNames[2]); 797 } 798 } 799 break; 800 } 801 802 case EVENT_POLL_STATE_NETWORK_SELECTION_MODE: { 803 ints = (int[])ar.result; 804 mNewSS.setIsManualSelection(ints[0] == 1); 805 break; 806 } 807 } 808 809 } catch (RuntimeException ex) { 810 loge("Exception while polling service state. Probably malformed RIL response." + ex); 811 } 812 813 mPollingContext[0]--; 814 815 if (mPollingContext[0] == 0) { 816 /** 817 * Since the roaming state of gsm service (from +CREG) and 818 * data service (from +CGREG) could be different, the new SS 819 * is set to roaming when either is true. 820 * 821 * There are exceptions for the above rule. 822 * The new SS is not set as roaming while gsm service reports 823 * roaming but indeed it is same operator. 824 * And the operator is considered non roaming. 825 * 826 * The test for the operators is to handle special roaming 827 * agreements and MVNO's. 828 */ 829 boolean roaming = (mGsmRoaming || mDataRoaming); 830 if ((mGsmRoaming && isSameNamedOperators(mNewSS) 831 && !isSameNamedOperatorConsideredRoaming(mNewSS)) 832 || isOperatorConsideredNonRoaming(mNewSS)) { 833 roaming = false; 834 } 835 mNewSS.setRoaming(roaming); 836 mNewSS.setEmergencyOnly(mEmergencyOnly); 837 pollStateDone(); 838 } 839 } 840 841 private void setSignalStrengthDefaultValues() { 842 mSignalStrength = new SignalStrength(true); 843 } 844 845 /** 846 * A complete "service state" from our perspective is 847 * composed of a handful of separate requests to the radio. 848 * 849 * We make all of these requests at once, but then abandon them 850 * and start over again if the radio notifies us that some 851 * event has changed 852 */ 853 @Override 854 public void pollState() { 855 mPollingContext = new int[1]; 856 mPollingContext[0] = 0; 857 858 switch (mCi.getRadioState()) { 859 case RADIO_UNAVAILABLE: 860 mNewSS.setStateOutOfService(); 861 mNewCellLoc.setStateInvalid(); 862 setSignalStrengthDefaultValues(); 863 mGotCountryCode = false; 864 mNitzUpdatedTime = false; 865 pollStateDone(); 866 break; 867 868 case RADIO_OFF: 869 mNewSS.setStateOff(); 870 mNewCellLoc.setStateInvalid(); 871 setSignalStrengthDefaultValues(); 872 mGotCountryCode = false; 873 mNitzUpdatedTime = false; 874 pollStateDone(); 875 break; 876 877 default: 878 // Issue all poll-related commands at once 879 // then count down the responses, which 880 // are allowed to arrive out-of-order 881 882 mPollingContext[0]++; 883 mCi.getOperator( 884 obtainMessage( 885 EVENT_POLL_STATE_OPERATOR, mPollingContext)); 886 887 mPollingContext[0]++; 888 mCi.getDataRegistrationState( 889 obtainMessage( 890 EVENT_POLL_STATE_GPRS, mPollingContext)); 891 892 mPollingContext[0]++; 893 mCi.getVoiceRegistrationState( 894 obtainMessage( 895 EVENT_POLL_STATE_REGISTRATION, mPollingContext)); 896 897 mPollingContext[0]++; 898 mCi.getNetworkSelectionMode( 899 obtainMessage( 900 EVENT_POLL_STATE_NETWORK_SELECTION_MODE, mPollingContext)); 901 break; 902 } 903 } 904 905 private void pollStateDone() { 906 if (DBG) { 907 log("Poll ServiceState done: " + 908 " oldSS=[" + mSS + "] newSS=[" + mNewSS + "]" + 909 " oldMaxDataCalls=" + mMaxDataCalls + 910 " mNewMaxDataCalls=" + mNewMaxDataCalls + 911 " oldReasonDataDenied=" + mReasonDataDenied + 912 " mNewReasonDataDenied=" + mNewReasonDataDenied); 913 } 914 915 if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) { 916 mNewSS.setRoaming(true); 917 } 918 919 useDataRegStateForDataOnlyDevices(); 920 921 boolean hasRegistered = 922 mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE 923 && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; 924 925 boolean hasDeregistered = 926 mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE 927 && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE; 928 929 boolean hasGprsAttached = 930 mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE 931 && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE; 932 933 boolean hasGprsDetached = 934 mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE 935 && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE; 936 937 boolean hasDataRegStateChanged = 938 mSS.getDataRegState() != mNewSS.getDataRegState(); 939 940 boolean hasVoiceRegStateChanged = 941 mSS.getVoiceRegState() != mNewSS.getVoiceRegState(); 942 943 boolean hasRilVoiceRadioTechnologyChanged = 944 mSS.getRilVoiceRadioTechnology() != mNewSS.getRilVoiceRadioTechnology(); 945 946 boolean hasRilDataRadioTechnologyChanged = 947 mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology(); 948 949 boolean hasChanged = !mNewSS.equals(mSS); 950 951 boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming(); 952 953 boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming(); 954 955 boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc); 956 957 // Add an event log when connection state changes 958 if (hasVoiceRegStateChanged || hasDataRegStateChanged) { 959 EventLog.writeEvent(EventLogTags.GSM_SERVICE_STATE_CHANGE, 960 mSS.getVoiceRegState(), mSS.getDataRegState(), 961 mNewSS.getVoiceRegState(), mNewSS.getDataRegState()); 962 } 963 964 // Add an event log when network type switched 965 // TODO: we may add filtering to reduce the event logged, 966 // i.e. check preferred network setting, only switch to 2G, etc 967 if (hasRilVoiceRadioTechnologyChanged) { 968 int cid = -1; 969 GsmCellLocation loc = mNewCellLoc; 970 if (loc != null) cid = loc.getCid(); 971 // NOTE: this code was previously located after mSS and mNewSS are swapped, so 972 // existing logs were incorrectly using the new state for "network_from" 973 // and STATE_OUT_OF_SERVICE for "network_to". To avoid confusion, use a new log tag 974 // to record the correct states. 975 EventLog.writeEvent(EventLogTags.GSM_RAT_SWITCHED_NEW, cid, 976 mSS.getRilVoiceRadioTechnology(), 977 mNewSS.getRilVoiceRadioTechnology()); 978 if (DBG) { 979 log("RAT switched " 980 + ServiceState.rilRadioTechnologyToString(mSS.getRilVoiceRadioTechnology()) 981 + " -> " 982 + ServiceState.rilRadioTechnologyToString( 983 mNewSS.getRilVoiceRadioTechnology()) + " at cell " + cid); 984 } 985 } 986 987 // swap mSS and mNewSS to put new state in mSS 988 ServiceState tss = mSS; 989 mSS = mNewSS; 990 mNewSS = tss; 991 // clean slate for next time 992 mNewSS.setStateOutOfService(); 993 994 // swap mCellLoc and mNewCellLoc to put new state in mCellLoc 995 GsmCellLocation tcl = mCellLoc; 996 mCellLoc = mNewCellLoc; 997 mNewCellLoc = tcl; 998 999 mReasonDataDenied = mNewReasonDataDenied; 1000 mMaxDataCalls = mNewMaxDataCalls; 1001 1002 if (hasRilVoiceRadioTechnologyChanged) { 1003 updatePhoneObject(); 1004 } 1005 1006 if (hasRilDataRadioTechnologyChanged) { 1007 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, 1008 ServiceState.rilRadioTechnologyToString(mSS.getRilVoiceRadioTechnology())); 1009 } 1010 1011 if (hasRegistered) { 1012 mNetworkAttachedRegistrants.notifyRegistrants(); 1013 1014 if (DBG) { 1015 log("pollStateDone: registering current mNitzUpdatedTime=" + 1016 mNitzUpdatedTime + " changing to false"); 1017 } 1018 mNitzUpdatedTime = false; 1019 } 1020 1021 if (hasChanged) { 1022 String operatorNumeric; 1023 1024 updateSpnDisplay(); 1025 1026 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, 1027 mSS.getOperatorAlphaLong()); 1028 1029 String prevOperatorNumeric = 1030 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, ""); 1031 operatorNumeric = mSS.getOperatorNumeric(); 1032 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric); 1033 updateCarrierMccMncConfiguration(operatorNumeric, 1034 prevOperatorNumeric, mPhone.getContext()); 1035 if (operatorNumeric == null) { 1036 if (DBG) log("operatorNumeric is null"); 1037 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); 1038 mGotCountryCode = false; 1039 mNitzUpdatedTime = false; 1040 } else { 1041 String iso = ""; 1042 String mcc = ""; 1043 try{ 1044 mcc = operatorNumeric.substring(0, 3); 1045 iso = MccTable.countryCodeForMcc(Integer.parseInt(mcc)); 1046 } catch ( NumberFormatException ex){ 1047 loge("pollStateDone: countryCodeForMcc error" + ex); 1048 } catch ( StringIndexOutOfBoundsException ex) { 1049 loge("pollStateDone: countryCodeForMcc error" + ex); 1050 } 1051 1052 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, iso); 1053 mGotCountryCode = true; 1054 1055 TimeZone zone = null; 1056 1057 if (!mNitzUpdatedTime && !mcc.equals("000") && !TextUtils.isEmpty(iso) && 1058 getAutoTimeZone()) { 1059 1060 // Test both paths if ignore nitz is true 1061 boolean testOneUniqueOffsetPath = SystemProperties.getBoolean( 1062 TelephonyProperties.PROPERTY_IGNORE_NITZ, false) && 1063 ((SystemClock.uptimeMillis() & 1) == 0); 1064 1065 ArrayList<TimeZone> uniqueZones = TimeUtils.getTimeZonesWithUniqueOffsets(iso); 1066 if ((uniqueZones.size() == 1) || testOneUniqueOffsetPath) { 1067 zone = uniqueZones.get(0); 1068 if (DBG) { 1069 log("pollStateDone: no nitz but one TZ for iso-cc=" + iso + 1070 " with zone.getID=" + zone.getID() + 1071 " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath); 1072 } 1073 setAndBroadcastNetworkSetTimeZone(zone.getID()); 1074 } else { 1075 if (DBG) { 1076 log("pollStateDone: there are " + uniqueZones.size() + 1077 " unique offsets for iso-cc='" + iso + 1078 " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath + 1079 "', do nothing"); 1080 } 1081 } 1082 } 1083 1084 if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric, 1085 mNeedFixZoneAfterNitz)) { 1086 // If the offset is (0, false) and the timezone property 1087 // is set, use the timezone property rather than 1088 // GMT. 1089 String zoneName = SystemProperties.get(TIMEZONE_PROPERTY); 1090 if (DBG) { 1091 log("pollStateDone: fix time zone zoneName='" + zoneName + 1092 "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst + 1093 " iso-cc='" + iso + 1094 "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, iso)); 1095 } 1096 1097 // "(mZoneOffset == 0) && (mZoneDst == false) && 1098 // (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)" 1099 // means that we received a NITZ string telling 1100 // it is in GMT+0 w/ DST time zone 1101 // BUT iso tells is NOT, e.g, a wrong NITZ reporting 1102 // local time w/ 0 offset. 1103 if ((mZoneOffset == 0) && (mZoneDst == false) && 1104 (zoneName != null) && (zoneName.length() > 0) && 1105 (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)) { 1106 zone = TimeZone.getDefault(); 1107 if (mNeedFixZoneAfterNitz) { 1108 // For wrong NITZ reporting local time w/ 0 offset, 1109 // need adjust time to reflect default timezone setting 1110 long ctm = System.currentTimeMillis(); 1111 long tzOffset = zone.getOffset(ctm); 1112 if (DBG) { 1113 log("pollStateDone: tzOffset=" + tzOffset + " ltod=" + 1114 TimeUtils.logTimeOfDay(ctm)); 1115 } 1116 if (getAutoTime()) { 1117 long adj = ctm - tzOffset; 1118 if (DBG) log("pollStateDone: adj ltod=" + 1119 TimeUtils.logTimeOfDay(adj)); 1120 setAndBroadcastNetworkSetTime(adj); 1121 } else { 1122 // Adjust the saved NITZ time to account for tzOffset. 1123 mSavedTime = mSavedTime - tzOffset; 1124 } 1125 } 1126 if (DBG) log("pollStateDone: using default TimeZone"); 1127 } else if (iso.equals("")){ 1128 // Country code not found. This is likely a test network. 1129 // Get a TimeZone based only on the NITZ parameters (best guess). 1130 zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime); 1131 if (DBG) log("pollStateDone: using NITZ TimeZone"); 1132 } else { 1133 zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, iso); 1134 if (DBG) log("pollStateDone: using getTimeZone(off, dst, time, iso)"); 1135 } 1136 1137 mNeedFixZoneAfterNitz = false; 1138 1139 if (zone != null) { 1140 log("pollStateDone: zone != null zone.getID=" + zone.getID()); 1141 if (getAutoTimeZone()) { 1142 setAndBroadcastNetworkSetTimeZone(zone.getID()); 1143 } 1144 saveNitzTimeZone(zone.getID()); 1145 } else { 1146 log("pollStateDone: zone == null"); 1147 } 1148 } 1149 } 1150 1151 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, 1152 mSS.getRoaming() ? "true" : "false"); 1153 1154 mPhone.notifyServiceStateChanged(mSS); 1155 } 1156 1157 if (hasGprsAttached) { 1158 mAttachedRegistrants.notifyRegistrants(); 1159 } 1160 1161 if (hasGprsDetached) { 1162 mDetachedRegistrants.notifyRegistrants(); 1163 } 1164 1165 if (hasDataRegStateChanged || hasRilDataRadioTechnologyChanged) { 1166 notifyDataRegStateRilRadioTechnologyChanged(); 1167 mPhone.notifyDataConnection(null); 1168 } 1169 1170 if (hasRoamingOn) { 1171 mRoamingOnRegistrants.notifyRegistrants(); 1172 } 1173 1174 if (hasRoamingOff) { 1175 mRoamingOffRegistrants.notifyRegistrants(); 1176 } 1177 1178 if (hasLocationChanged) { 1179 mPhone.notifyLocationChanged(); 1180 } 1181 1182 if (! isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) { 1183 if (!mStartedGprsRegCheck && !mReportedGprsNoReg) { 1184 mStartedGprsRegCheck = true; 1185 1186 int check_period = Settings.Global.getInt( 1187 mPhone.getContext().getContentResolver(), 1188 Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS, 1189 DEFAULT_GPRS_CHECK_PERIOD_MILLIS); 1190 sendMessageDelayed(obtainMessage(EVENT_CHECK_REPORT_GPRS), 1191 check_period); 1192 } 1193 } else { 1194 mReportedGprsNoReg = false; 1195 } 1196 // TODO: Add GsmCellIdenity updating, see CdmaLteServiceStateTracker. 1197 } 1198 1199 /** 1200 * Check if GPRS got registered while voice is registered. 1201 * 1202 * @param dataRegState i.e. CGREG in GSM 1203 * @param voiceRegState i.e. CREG in GSM 1204 * @return false if device only register to voice but not gprs 1205 */ 1206 private boolean isGprsConsistent(int dataRegState, int voiceRegState) { 1207 return !((voiceRegState == ServiceState.STATE_IN_SERVICE) && 1208 (dataRegState != ServiceState.STATE_IN_SERVICE)); 1209 } 1210 1211 /** 1212 * Returns a TimeZone object based only on parameters from the NITZ string. 1213 */ 1214 private TimeZone getNitzTimeZone(int offset, boolean dst, long when) { 1215 TimeZone guess = findTimeZone(offset, dst, when); 1216 if (guess == null) { 1217 // Couldn't find a proper timezone. Perhaps the DST data is wrong. 1218 guess = findTimeZone(offset, !dst, when); 1219 } 1220 if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID())); 1221 return guess; 1222 } 1223 1224 private TimeZone findTimeZone(int offset, boolean dst, long when) { 1225 int rawOffset = offset; 1226 if (dst) { 1227 rawOffset -= 3600000; 1228 } 1229 String[] zones = TimeZone.getAvailableIDs(rawOffset); 1230 TimeZone guess = null; 1231 Date d = new Date(when); 1232 for (String zone : zones) { 1233 TimeZone tz = TimeZone.getTimeZone(zone); 1234 if (tz.getOffset(when) == offset && 1235 tz.inDaylightTime(d) == dst) { 1236 guess = tz; 1237 break; 1238 } 1239 } 1240 1241 return guess; 1242 } 1243 1244 private void queueNextSignalStrengthPoll() { 1245 if (mDontPollSignalStrength) { 1246 // The radio is telling us about signal strength changes 1247 // we don't have to ask it 1248 return; 1249 } 1250 1251 Message msg; 1252 1253 msg = obtainMessage(); 1254 msg.what = EVENT_POLL_SIGNAL_STRENGTH; 1255 1256 long nextTime; 1257 1258 // TODO Don't poll signal strength if screen is off 1259 sendMessageDelayed(msg, POLL_PERIOD_MILLIS); 1260 } 1261 1262 /** 1263 * Set restricted state based on the OnRestrictedStateChanged notification 1264 * If any voice or packet restricted state changes, trigger a UI 1265 * notification and notify registrants when sim is ready. 1266 * 1267 * @param ar an int value of RIL_RESTRICTED_STATE_* 1268 */ 1269 private void onRestrictedStateChanged(AsyncResult ar) { 1270 RestrictedState newRs = new RestrictedState(); 1271 1272 if (DBG) log("onRestrictedStateChanged: E rs "+ mRestrictedState); 1273 1274 if (ar.exception == null) { 1275 int[] ints = (int[])ar.result; 1276 int state = ints[0]; 1277 1278 newRs.setCsEmergencyRestricted( 1279 ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) || 1280 ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); 1281 //ignore the normal call and data restricted state before SIM READY 1282 if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY) { 1283 newRs.setCsNormalRestricted( 1284 ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) || 1285 ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); 1286 newRs.setPsRestricted( 1287 (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0); 1288 } 1289 1290 if (DBG) log("onRestrictedStateChanged: new rs "+ newRs); 1291 1292 if (!mRestrictedState.isPsRestricted() && newRs.isPsRestricted()) { 1293 mPsRestrictEnabledRegistrants.notifyRegistrants(); 1294 setNotification(PS_ENABLED); 1295 } else if (mRestrictedState.isPsRestricted() && !newRs.isPsRestricted()) { 1296 mPsRestrictDisabledRegistrants.notifyRegistrants(); 1297 setNotification(PS_DISABLED); 1298 } 1299 1300 /** 1301 * There are two kind of cs restriction, normal and emergency. So 1302 * there are 4 x 4 combinations in current and new restricted states 1303 * and we only need to notify when state is changed. 1304 */ 1305 if (mRestrictedState.isCsRestricted()) { 1306 if (!newRs.isCsRestricted()) { 1307 // remove all restriction 1308 setNotification(CS_DISABLED); 1309 } else if (!newRs.isCsNormalRestricted()) { 1310 // remove normal restriction 1311 setNotification(CS_EMERGENCY_ENABLED); 1312 } else if (!newRs.isCsEmergencyRestricted()) { 1313 // remove emergency restriction 1314 setNotification(CS_NORMAL_ENABLED); 1315 } 1316 } else if (mRestrictedState.isCsEmergencyRestricted() && 1317 !mRestrictedState.isCsNormalRestricted()) { 1318 if (!newRs.isCsRestricted()) { 1319 // remove all restriction 1320 setNotification(CS_DISABLED); 1321 } else if (newRs.isCsRestricted()) { 1322 // enable all restriction 1323 setNotification(CS_ENABLED); 1324 } else if (newRs.isCsNormalRestricted()) { 1325 // remove emergency restriction and enable normal restriction 1326 setNotification(CS_NORMAL_ENABLED); 1327 } 1328 } else if (!mRestrictedState.isCsEmergencyRestricted() && 1329 mRestrictedState.isCsNormalRestricted()) { 1330 if (!newRs.isCsRestricted()) { 1331 // remove all restriction 1332 setNotification(CS_DISABLED); 1333 } else if (newRs.isCsRestricted()) { 1334 // enable all restriction 1335 setNotification(CS_ENABLED); 1336 } else if (newRs.isCsEmergencyRestricted()) { 1337 // remove normal restriction and enable emergency restriction 1338 setNotification(CS_EMERGENCY_ENABLED); 1339 } 1340 } else { 1341 if (newRs.isCsRestricted()) { 1342 // enable all restriction 1343 setNotification(CS_ENABLED); 1344 } else if (newRs.isCsEmergencyRestricted()) { 1345 // enable emergency restriction 1346 setNotification(CS_EMERGENCY_ENABLED); 1347 } else if (newRs.isCsNormalRestricted()) { 1348 // enable normal restriction 1349 setNotification(CS_NORMAL_ENABLED); 1350 } 1351 } 1352 1353 mRestrictedState = newRs; 1354 } 1355 log("onRestrictedStateChanged: X rs "+ mRestrictedState); 1356 } 1357 1358 /** code is registration state 0-5 from TS 27.007 7.2 */ 1359 private int regCodeToServiceState(int code) { 1360 switch (code) { 1361 case 0: 1362 case 2: // 2 is "searching" 1363 case 3: // 3 is "registration denied" 1364 case 4: // 4 is "unknown" no vaild in current baseband 1365 case 10:// same as 0, but indicates that emergency call is possible. 1366 case 12:// same as 2, but indicates that emergency call is possible. 1367 case 13:// same as 3, but indicates that emergency call is possible. 1368 case 14:// same as 4, but indicates that emergency call is possible. 1369 return ServiceState.STATE_OUT_OF_SERVICE; 1370 1371 case 1: 1372 return ServiceState.STATE_IN_SERVICE; 1373 1374 case 5: 1375 // in service, roam 1376 return ServiceState.STATE_IN_SERVICE; 1377 1378 default: 1379 loge("regCodeToServiceState: unexpected service state " + code); 1380 return ServiceState.STATE_OUT_OF_SERVICE; 1381 } 1382 } 1383 1384 1385 /** 1386 * code is registration state 0-5 from TS 27.007 7.2 1387 * returns true if registered roam, false otherwise 1388 */ 1389 private boolean regCodeIsRoaming (int code) { 1390 return ServiceState.RIL_REG_STATE_ROAMING == code; 1391 } 1392 1393 /** 1394 * Set roaming state if operator mcc is the same as sim mcc 1395 * and ons is different from spn 1396 * 1397 * @param s ServiceState hold current ons 1398 * @return true if same operator 1399 */ 1400 private boolean isSameNamedOperators(ServiceState s) { 1401 String spn = getSystemProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "empty"); 1402 1403 String onsl = s.getOperatorAlphaLong(); 1404 String onss = s.getOperatorAlphaShort(); 1405 1406 boolean equalsOnsl = onsl != null && spn.equals(onsl); 1407 boolean equalsOnss = onss != null && spn.equals(onss); 1408 1409 return currentMccEqualsSimMcc(s) && (equalsOnsl || equalsOnss); 1410 } 1411 1412 /** 1413 * Compare SIM MCC with Operator MCC 1414 * 1415 * @param s ServiceState hold current ons 1416 * @return true if both are same 1417 */ 1418 private boolean currentMccEqualsSimMcc(ServiceState s) { 1419 String simNumeric = getSystemProperty( 1420 TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, ""); 1421 String operatorNumeric = s.getOperatorNumeric(); 1422 boolean equalsMcc = true; 1423 1424 try { 1425 equalsMcc = simNumeric.substring(0, 3). 1426 equals(operatorNumeric.substring(0, 3)); 1427 } catch (Exception e){ 1428 } 1429 return equalsMcc; 1430 } 1431 1432 /** 1433 * Do not set roaming state in case of oprators considered non-roaming. 1434 * 1435 + Can use mcc or mcc+mnc as item of config_operatorConsideredNonRoaming. 1436 * For example, 302 or 21407. If mcc or mcc+mnc match with operator, 1437 * don't set roaming state. 1438 * 1439 * @param s ServiceState hold current ons 1440 * @return false for roaming state set 1441 */ 1442 private boolean isOperatorConsideredNonRoaming(ServiceState s) { 1443 String operatorNumeric = s.getOperatorNumeric(); 1444 String[] numericArray = mPhone.getContext().getResources().getStringArray( 1445 com.android.internal.R.array.config_operatorConsideredNonRoaming); 1446 1447 if (numericArray.length == 0 || operatorNumeric == null) { 1448 return false; 1449 } 1450 1451 for (String numeric : numericArray) { 1452 if (operatorNumeric.startsWith(numeric)) { 1453 return true; 1454 } 1455 } 1456 return false; 1457 } 1458 1459 private boolean isSameNamedOperatorConsideredRoaming(ServiceState s) { 1460 String operatorNumeric = s.getOperatorNumeric(); 1461 String[] numericArray = mPhone.getContext().getResources().getStringArray( 1462 com.android.internal.R.array.config_sameNamedOperatorConsideredRoaming); 1463 1464 if (numericArray.length == 0 || operatorNumeric == null) { 1465 return false; 1466 } 1467 1468 for (String numeric : numericArray) { 1469 if (operatorNumeric.startsWith(numeric)) { 1470 return true; 1471 } 1472 } 1473 return false; 1474 } 1475 1476 /** 1477 * @return The current GPRS state. IN_SERVICE is the same as "attached" 1478 * and OUT_OF_SERVICE is the same as detached. 1479 */ 1480 @Override 1481 public int getCurrentDataConnectionState() { 1482 return mSS.getDataRegState(); 1483 } 1484 1485 /** 1486 * @return true if phone is camping on a technology (eg UMTS) 1487 * that could support voice and data simultaneously. 1488 */ 1489 @Override 1490 public boolean isConcurrentVoiceAndDataAllowed() { 1491 return (mSS.getRilVoiceRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_UMTS); 1492 } 1493 1494 /** 1495 * @return the current cell location information. Prefer Gsm location 1496 * information if available otherwise return LTE location information 1497 */ 1498 public CellLocation getCellLocation() { 1499 if ((mCellLoc.getLac() >= 0) && (mCellLoc.getCid() >= 0)) { 1500 if (DBG) log("getCellLocation(): X good mCellLoc=" + mCellLoc); 1501 return mCellLoc; 1502 } else { 1503 List<CellInfo> result = getAllCellInfo(); 1504 if (result != null) { 1505 // A hack to allow tunneling of LTE information via GsmCellLocation 1506 // so that older Network Location Providers can return some information 1507 // on LTE only networks, see bug 9228974. 1508 // 1509 // We'll search the return CellInfo array preferring GSM/WCDMA 1510 // data, but if there is none we'll tunnel the first LTE information 1511 // in the list. 1512 // 1513 // The tunnel'd LTE information is returned as follows: 1514 // LAC = TAC field 1515 // CID = CI field 1516 // PSC = 0. 1517 GsmCellLocation cellLocOther = new GsmCellLocation(); 1518 for (CellInfo ci : result) { 1519 if (ci instanceof CellInfoGsm) { 1520 CellInfoGsm cellInfoGsm = (CellInfoGsm)ci; 1521 CellIdentityGsm cellIdentityGsm = cellInfoGsm.getCellIdentity(); 1522 cellLocOther.setLacAndCid(cellIdentityGsm.getLac(), 1523 cellIdentityGsm.getCid()); 1524 cellLocOther.setPsc(cellIdentityGsm.getPsc()); 1525 if (DBG) log("getCellLocation(): X ret GSM info=" + cellLocOther); 1526 return cellLocOther; 1527 } else if (ci instanceof CellInfoWcdma) { 1528 CellInfoWcdma cellInfoWcdma = (CellInfoWcdma)ci; 1529 CellIdentityWcdma cellIdentityWcdma = cellInfoWcdma.getCellIdentity(); 1530 cellLocOther.setLacAndCid(cellIdentityWcdma.getLac(), 1531 cellIdentityWcdma.getCid()); 1532 cellLocOther.setPsc(cellIdentityWcdma.getPsc()); 1533 if (DBG) log("getCellLocation(): X ret WCDMA info=" + cellLocOther); 1534 return cellLocOther; 1535 } else if ((ci instanceof CellInfoLte) && 1536 ((cellLocOther.getLac() < 0) || (cellLocOther.getCid() < 0))) { 1537 // We'll return the first good LTE info we get if there is no better answer 1538 CellInfoLte cellInfoLte = (CellInfoLte)ci; 1539 CellIdentityLte cellIdentityLte = cellInfoLte.getCellIdentity(); 1540 if ((cellIdentityLte.getTac() != Integer.MAX_VALUE) 1541 && (cellIdentityLte.getCi() != Integer.MAX_VALUE)) { 1542 cellLocOther.setLacAndCid(cellIdentityLte.getTac(), 1543 cellIdentityLte.getCi()); 1544 cellLocOther.setPsc(0); 1545 if (DBG) { 1546 log("getCellLocation(): possible LTE cellLocOther=" + cellLocOther); 1547 } 1548 } 1549 } 1550 } 1551 if (DBG) { 1552 log("getCellLocation(): X ret best answer cellLocOther=" + cellLocOther); 1553 } 1554 return cellLocOther; 1555 } else { 1556 if (DBG) { 1557 log("getCellLocation(): X empty mCellLoc and CellInfo mCellLoc=" + mCellLoc); 1558 } 1559 return mCellLoc; 1560 } 1561 } 1562 } 1563 1564 /** 1565 * nitzReceiveTime is time_t that the NITZ time was posted 1566 */ 1567 private void setTimeFromNITZString (String nitz, long nitzReceiveTime) { 1568 // "yy/mm/dd,hh:mm:ss(+/-)tz" 1569 // tz is in number of quarter-hours 1570 1571 long start = SystemClock.elapsedRealtime(); 1572 if (DBG) {log("NITZ: " + nitz + "," + nitzReceiveTime + 1573 " start=" + start + " delay=" + (start - nitzReceiveTime)); 1574 } 1575 1576 try { 1577 /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone 1578 * offset as well (which we won't worry about until later) */ 1579 Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT")); 1580 1581 c.clear(); 1582 c.set(Calendar.DST_OFFSET, 0); 1583 1584 String[] nitzSubs = nitz.split("[/:,+-]"); 1585 1586 int year = 2000 + Integer.parseInt(nitzSubs[0]); 1587 c.set(Calendar.YEAR, year); 1588 1589 // month is 0 based! 1590 int month = Integer.parseInt(nitzSubs[1]) - 1; 1591 c.set(Calendar.MONTH, month); 1592 1593 int date = Integer.parseInt(nitzSubs[2]); 1594 c.set(Calendar.DATE, date); 1595 1596 int hour = Integer.parseInt(nitzSubs[3]); 1597 c.set(Calendar.HOUR, hour); 1598 1599 int minute = Integer.parseInt(nitzSubs[4]); 1600 c.set(Calendar.MINUTE, minute); 1601 1602 int second = Integer.parseInt(nitzSubs[5]); 1603 c.set(Calendar.SECOND, second); 1604 1605 boolean sign = (nitz.indexOf('-') == -1); 1606 1607 int tzOffset = Integer.parseInt(nitzSubs[6]); 1608 1609 int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7]) 1610 : 0; 1611 1612 // The zone offset received from NITZ is for current local time, 1613 // so DST correction is already applied. Don't add it again. 1614 // 1615 // tzOffset += dst * 4; 1616 // 1617 // We could unapply it if we wanted the raw offset. 1618 1619 tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000; 1620 1621 TimeZone zone = null; 1622 1623 // As a special extension, the Android emulator appends the name of 1624 // the host computer's timezone to the nitz string. this is zoneinfo 1625 // timezone name of the form Area!Location or Area!Location!SubLocation 1626 // so we need to convert the ! into / 1627 if (nitzSubs.length >= 9) { 1628 String tzname = nitzSubs[8].replace('!','/'); 1629 zone = TimeZone.getTimeZone( tzname ); 1630 } 1631 1632 String iso = getSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); 1633 1634 if (zone == null) { 1635 1636 if (mGotCountryCode) { 1637 if (iso != null && iso.length() > 0) { 1638 zone = TimeUtils.getTimeZone(tzOffset, dst != 0, 1639 c.getTimeInMillis(), 1640 iso); 1641 } else { 1642 // We don't have a valid iso country code. This is 1643 // most likely because we're on a test network that's 1644 // using a bogus MCC (eg, "001"), so get a TimeZone 1645 // based only on the NITZ parameters. 1646 zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis()); 1647 } 1648 } 1649 } 1650 1651 if ((zone == null) || (mZoneOffset != tzOffset) || (mZoneDst != (dst != 0))){ 1652 // We got the time before the country or the zone has changed 1653 // so we don't know how to identify the DST rules yet. Save 1654 // the information and hope to fix it up later. 1655 1656 mNeedFixZoneAfterNitz = true; 1657 mZoneOffset = tzOffset; 1658 mZoneDst = dst != 0; 1659 mZoneTime = c.getTimeInMillis(); 1660 } 1661 1662 if (zone != null) { 1663 if (getAutoTimeZone()) { 1664 setAndBroadcastNetworkSetTimeZone(zone.getID()); 1665 } 1666 saveNitzTimeZone(zone.getID()); 1667 } 1668 1669 String ignore = SystemProperties.get("gsm.ignore-nitz"); 1670 if (ignore != null && ignore.equals("yes")) { 1671 log("NITZ: Not setting clock because gsm.ignore-nitz is set"); 1672 return; 1673 } 1674 1675 try { 1676 mWakeLock.acquire(); 1677 1678 if (getAutoTime()) { 1679 long millisSinceNitzReceived 1680 = SystemClock.elapsedRealtime() - nitzReceiveTime; 1681 1682 if (millisSinceNitzReceived < 0) { 1683 // Sanity check: something is wrong 1684 if (DBG) { 1685 log("NITZ: not setting time, clock has rolled " 1686 + "backwards since NITZ time was received, " 1687 + nitz); 1688 } 1689 return; 1690 } 1691 1692 if (millisSinceNitzReceived > Integer.MAX_VALUE) { 1693 // If the time is this far off, something is wrong > 24 days! 1694 if (DBG) { 1695 log("NITZ: not setting time, processing has taken " 1696 + (millisSinceNitzReceived / (1000 * 60 * 60 * 24)) 1697 + " days"); 1698 } 1699 return; 1700 } 1701 1702 // Note: with range checks above, cast to int is safe 1703 c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived); 1704 1705 if (DBG) { 1706 log("NITZ: Setting time of day to " + c.getTime() 1707 + " NITZ receive delay(ms): " + millisSinceNitzReceived 1708 + " gained(ms): " 1709 + (c.getTimeInMillis() - System.currentTimeMillis()) 1710 + " from " + nitz); 1711 } 1712 1713 setAndBroadcastNetworkSetTime(c.getTimeInMillis()); 1714 Rlog.i(LOG_TAG, "NITZ: after Setting time of day"); 1715 } 1716 SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis())); 1717 saveNitzTime(c.getTimeInMillis()); 1718 if (VDBG) { 1719 long end = SystemClock.elapsedRealtime(); 1720 log("NITZ: end=" + end + " dur=" + (end - start)); 1721 } 1722 mNitzUpdatedTime = true; 1723 } finally { 1724 mWakeLock.release(); 1725 } 1726 } catch (RuntimeException ex) { 1727 loge("NITZ: Parsing NITZ time " + nitz + " ex=" + ex); 1728 } 1729 } 1730 1731 private boolean getAutoTime() { 1732 try { 1733 return Settings.Global.getInt(mPhone.getContext().getContentResolver(), 1734 Settings.Global.AUTO_TIME) > 0; 1735 } catch (SettingNotFoundException snfe) { 1736 return true; 1737 } 1738 } 1739 1740 private boolean getAutoTimeZone() { 1741 try { 1742 return Settings.Global.getInt(mPhone.getContext().getContentResolver(), 1743 Settings.Global.AUTO_TIME_ZONE) > 0; 1744 } catch (SettingNotFoundException snfe) { 1745 return true; 1746 } 1747 } 1748 1749 private void saveNitzTimeZone(String zoneId) { 1750 mSavedTimeZone = zoneId; 1751 } 1752 1753 private void saveNitzTime(long time) { 1754 mSavedTime = time; 1755 mSavedAtTime = SystemClock.elapsedRealtime(); 1756 } 1757 1758 /** 1759 * Set the timezone and send out a sticky broadcast so the system can 1760 * determine if the timezone was set by the carrier. 1761 * 1762 * @param zoneId timezone set by carrier 1763 */ 1764 private void setAndBroadcastNetworkSetTimeZone(String zoneId) { 1765 if (DBG) log("setAndBroadcastNetworkSetTimeZone: setTimeZone=" + zoneId); 1766 AlarmManager alarm = 1767 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); 1768 alarm.setTimeZone(zoneId); 1769 Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); 1770 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 1771 intent.putExtra("time-zone", zoneId); 1772 mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1773 if (DBG) { 1774 log("setAndBroadcastNetworkSetTimeZone: call alarm.setTimeZone and broadcast zoneId=" + 1775 zoneId); 1776 } 1777 } 1778 1779 /** 1780 * Set the time and Send out a sticky broadcast so the system can determine 1781 * if the time was set by the carrier. 1782 * 1783 * @param time time set by network 1784 */ 1785 private void setAndBroadcastNetworkSetTime(long time) { 1786 if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms"); 1787 SystemClock.setCurrentTimeMillis(time); 1788 Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME); 1789 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 1790 intent.putExtra("time", time); 1791 mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1792 } 1793 1794 private void revertToNitzTime() { 1795 if (Settings.Global.getInt(mPhone.getContext().getContentResolver(), 1796 Settings.Global.AUTO_TIME, 0) == 0) { 1797 return; 1798 } 1799 if (DBG) { 1800 log("Reverting to NITZ Time: mSavedTime=" + mSavedTime 1801 + " mSavedAtTime=" + mSavedAtTime); 1802 } 1803 if (mSavedTime != 0 && mSavedAtTime != 0) { 1804 setAndBroadcastNetworkSetTime(mSavedTime 1805 + (SystemClock.elapsedRealtime() - mSavedAtTime)); 1806 } 1807 } 1808 1809 private void revertToNitzTimeZone() { 1810 if (Settings.Global.getInt(mPhone.getContext().getContentResolver(), 1811 Settings.Global.AUTO_TIME_ZONE, 0) == 0) { 1812 return; 1813 } 1814 if (DBG) log("Reverting to NITZ TimeZone: tz='" + mSavedTimeZone); 1815 if (mSavedTimeZone != null) { 1816 setAndBroadcastNetworkSetTimeZone(mSavedTimeZone); 1817 } 1818 } 1819 1820 /** 1821 * Post a notification to NotificationManager for restricted state 1822 * 1823 * @param notifyType is one state of PS/CS_*_ENABLE/DISABLE 1824 */ 1825 private void setNotification(int notifyType) { 1826 1827 if (DBG) log("setNotification: create notification " + notifyType); 1828 Context context = mPhone.getContext(); 1829 1830 mNotification = new Notification(); 1831 mNotification.when = System.currentTimeMillis(); 1832 mNotification.flags = Notification.FLAG_AUTO_CANCEL; 1833 mNotification.icon = com.android.internal.R.drawable.stat_sys_warning; 1834 Intent intent = new Intent(); 1835 mNotification.contentIntent = PendingIntent 1836 .getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); 1837 1838 CharSequence details = ""; 1839 CharSequence title = context.getText(com.android.internal.R.string.RestrictedChangedTitle); 1840 int notificationId = CS_NOTIFICATION; 1841 1842 switch (notifyType) { 1843 case PS_ENABLED: 1844 notificationId = PS_NOTIFICATION; 1845 details = context.getText(com.android.internal.R.string.RestrictedOnData); 1846 break; 1847 case PS_DISABLED: 1848 notificationId = PS_NOTIFICATION; 1849 break; 1850 case CS_ENABLED: 1851 details = context.getText(com.android.internal.R.string.RestrictedOnAllVoice); 1852 break; 1853 case CS_NORMAL_ENABLED: 1854 details = context.getText(com.android.internal.R.string.RestrictedOnNormal); 1855 break; 1856 case CS_EMERGENCY_ENABLED: 1857 details = context.getText(com.android.internal.R.string.RestrictedOnEmergency); 1858 break; 1859 case CS_DISABLED: 1860 // do nothing and cancel the notification later 1861 break; 1862 } 1863 1864 if (DBG) log("setNotification: put notification " + title + " / " +details); 1865 mNotification.tickerText = title; 1866 mNotification.color = context.getResources().getColor( 1867 com.android.internal.R.color.system_notification_accent_color); 1868 mNotification.setLatestEventInfo(context, title, details, 1869 mNotification.contentIntent); 1870 1871 NotificationManager notificationManager = (NotificationManager) 1872 context.getSystemService(Context.NOTIFICATION_SERVICE); 1873 1874 if (notifyType == PS_DISABLED || notifyType == CS_DISABLED) { 1875 // cancel previous post notification 1876 notificationManager.cancel(notificationId); 1877 } else { 1878 // update restricted state notification 1879 notificationManager.notify(notificationId, mNotification); 1880 } 1881 } 1882 1883 private UiccCardApplication getUiccCardApplication() { 1884 return mUiccController.getUiccCardApplication(mPhone.getPhoneId(), 1885 UiccController.APP_FAM_3GPP); 1886 } 1887 1888 @Override 1889 protected void onUpdateIccAvailability() { 1890 if (mUiccController == null ) { 1891 return; 1892 } 1893 1894 UiccCardApplication newUiccApplication = getUiccCardApplication(); 1895 1896 if (mUiccApplcation != newUiccApplication) { 1897 if (mUiccApplcation != null) { 1898 log("Removing stale icc objects."); 1899 mUiccApplcation.unregisterForReady(this); 1900 if (mIccRecords != null) { 1901 mIccRecords.unregisterForRecordsLoaded(this); 1902 } 1903 mIccRecords = null; 1904 mUiccApplcation = null; 1905 } 1906 if (newUiccApplication != null) { 1907 log("New card found"); 1908 mUiccApplcation = newUiccApplication; 1909 mIccRecords = mUiccApplcation.getIccRecords(); 1910 mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null); 1911 if (mIccRecords != null) { 1912 mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); 1913 } 1914 } 1915 } 1916 } 1917 @Override 1918 protected void log(String s) { 1919 Rlog.d(LOG_TAG, "[GsmSST] " + s); 1920 } 1921 1922 @Override 1923 protected void loge(String s) { 1924 Rlog.e(LOG_TAG, "[GsmSST] " + s); 1925 } 1926 1927 @Override 1928 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1929 pw.println("GsmServiceStateTracker extends:"); 1930 super.dump(fd, pw, args); 1931 pw.println(" mPhone=" + mPhone); 1932 pw.println(" mSS=" + mSS); 1933 pw.println(" mNewSS=" + mNewSS); 1934 pw.println(" mCellLoc=" + mCellLoc); 1935 pw.println(" mNewCellLoc=" + mNewCellLoc); 1936 pw.println(" mPreferredNetworkType=" + mPreferredNetworkType); 1937 pw.println(" mMaxDataCalls=" + mMaxDataCalls); 1938 pw.println(" mNewMaxDataCalls=" + mNewMaxDataCalls); 1939 pw.println(" mReasonDataDenied=" + mReasonDataDenied); 1940 pw.println(" mNewReasonDataDenied=" + mNewReasonDataDenied); 1941 pw.println(" mGsmRoaming=" + mGsmRoaming); 1942 pw.println(" mDataRoaming=" + mDataRoaming); 1943 pw.println(" mEmergencyOnly=" + mEmergencyOnly); 1944 pw.println(" mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz); 1945 pw.println(" mZoneOffset=" + mZoneOffset); 1946 pw.println(" mZoneDst=" + mZoneDst); 1947 pw.println(" mZoneTime=" + mZoneTime); 1948 pw.println(" mGotCountryCode=" + mGotCountryCode); 1949 pw.println(" mNitzUpdatedTime=" + mNitzUpdatedTime); 1950 pw.println(" mSavedTimeZone=" + mSavedTimeZone); 1951 pw.println(" mSavedTime=" + mSavedTime); 1952 pw.println(" mSavedAtTime=" + mSavedAtTime); 1953 pw.println(" mStartedGprsRegCheck=" + mStartedGprsRegCheck); 1954 pw.println(" mReportedGprsNoReg=" + mReportedGprsNoReg); 1955 pw.println(" mNotification=" + mNotification); 1956 pw.println(" mWakeLock=" + mWakeLock); 1957 pw.println(" mCurSpn=" + mCurSpn); 1958 pw.println(" mCurShowSpn=" + mCurShowSpn); 1959 pw.println(" mCurPlmn=" + mCurPlmn); 1960 pw.println(" mCurShowPlmn=" + mCurShowPlmn); 1961 } 1962 1963 1964 /** 1965 * Clean up existing voice and data connection then turn off radio power. 1966 * 1967 * Hang up the existing voice calls to decrease call drop rate. 1968 */ 1969 @Override 1970 public void powerOffRadioSafely(DcTrackerBase dcTracker) { 1971 synchronized (this) { 1972 if (!mPendingRadioPowerOffAfterDataOff) { 1973 long dds = SubscriptionManager.getDefaultDataSubId(); 1974 // To minimize race conditions we call cleanUpAllConnections on 1975 // both if else paths instead of before this isDisconnected test. 1976 if (dcTracker.isDisconnected() 1977 && (dds == mPhone.getSubId() 1978 || (dds != mPhone.getSubId() 1979 && ProxyController.getInstance().isDataDisconnected(dds)))) { 1980 // To minimize race conditions we do this after isDisconnected 1981 dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF); 1982 if (DBG) log("Data disconnected, turn off radio right away."); 1983 hangupAndPowerOff(); 1984 } else { 1985 dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF); 1986 if (dds != mPhone.getSubId() 1987 && !ProxyController.getInstance().isDataDisconnected(dds)) { 1988 if (DBG) log("Data is active on DDS. Wait for all data disconnect"); 1989 // Data is not disconnected on DDS. Wait for the data disconnect complete 1990 // before sending the RADIO_POWER off. 1991 ProxyController.getInstance().registerForAllDataDisconnected(dds, this, 1992 EVENT_ALL_DATA_DISCONNECTED, null); 1993 mPendingRadioPowerOffAfterDataOff = true; 1994 } 1995 Message msg = Message.obtain(this); 1996 msg.what = EVENT_SET_RADIO_POWER_OFF; 1997 msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag; 1998 if (sendMessageDelayed(msg, 30000)) { 1999 if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio."); 2000 mPendingRadioPowerOffAfterDataOff = true; 2001 } else { 2002 log("Cannot send delayed Msg, turn off radio right away."); 2003 hangupAndPowerOff(); 2004 mPendingRadioPowerOffAfterDataOff = false; 2005 } 2006 } 2007 } 2008 } 2009 2010 } 2011 2012 public void setImsRegistrationState(boolean registered){ 2013 if (mImsRegistrationOnOff && !registered) { 2014 if (mAlarmSwitch) { 2015 mImsRegistrationOnOff = registered; 2016 2017 Context context = mPhone.getContext(); 2018 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 2019 am.cancel(mRadioOffIntent); 2020 mAlarmSwitch = false; 2021 2022 sendMessage(obtainMessage(EVENT_CHANGE_IMS_STATE)); 2023 return; 2024 } 2025 } 2026 mImsRegistrationOnOff = registered; 2027 } 2028} 2029