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