CDMAPhone.java revision ace9a749c5a2a5e07527f728b7331423d16c36cd
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.cdma; 18 19import android.app.ActivityManagerNative; 20import android.content.ContentValues; 21import android.content.Context; 22import android.content.Intent; 23import android.content.SharedPreferences; 24import android.database.SQLException; 25import android.net.Uri; 26import android.os.AsyncResult; 27import android.os.Handler; 28import android.os.Message; 29import android.os.PowerManager; 30import android.os.PowerManager.WakeLock; 31import android.os.Registrant; 32import android.os.RegistrantList; 33import android.os.SystemProperties; 34import android.os.UserHandle; 35import android.preference.PreferenceManager; 36import android.provider.Settings; 37import android.provider.Telephony; 38import android.telephony.CellLocation; 39import android.telephony.PhoneNumberUtils; 40import android.telephony.ServiceState; 41import android.telephony.cdma.CdmaCellLocation; 42import android.text.TextUtils; 43import android.telephony.Rlog; 44 45import com.android.internal.telephony.CallStateException; 46import com.android.internal.telephony.CallTracker; 47import com.android.internal.telephony.CommandException; 48import com.android.internal.telephony.CommandsInterface; 49import com.android.internal.telephony.Connection; 50import com.android.internal.telephony.IccPhoneBookInterfaceManager; 51import com.android.internal.telephony.IccSmsInterfaceManager; 52import com.android.internal.telephony.MccTable; 53import com.android.internal.telephony.MmiCode; 54import com.android.internal.telephony.OperatorInfo; 55import com.android.internal.telephony.PhoneBase; 56import com.android.internal.telephony.PhoneConstants; 57import com.android.internal.telephony.PhoneNotifier; 58import com.android.internal.telephony.PhoneProxy; 59import com.android.internal.telephony.PhoneSubInfo; 60import com.android.internal.telephony.ServiceStateTracker; 61import com.android.internal.telephony.SmsBroadcastUndelivered; 62import com.android.internal.telephony.TelephonyIntents; 63import com.android.internal.telephony.TelephonyProperties; 64import com.android.internal.telephony.UUSInfo; 65import com.android.internal.telephony.dataconnection.DcTracker; 66import com.android.internal.telephony.uicc.IccException; 67import com.android.internal.telephony.uicc.IccRecords; 68import com.android.internal.telephony.uicc.RuimRecords; 69import com.android.internal.telephony.uicc.UiccCardApplication; 70import com.android.internal.telephony.uicc.UiccController; 71import java.io.FileDescriptor; 72import java.io.PrintWriter; 73import java.util.ArrayList; 74import java.util.List; 75import java.util.regex.Matcher; 76import java.util.regex.Pattern; 77 78import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; 79import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; 80import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; 81 82/** 83 * {@hide} 84 */ 85public class CDMAPhone extends PhoneBase { 86 static final String LOG_TAG = "CDMAPhone"; 87 private static final boolean DBG = true; 88 private static final boolean VDBG = false; /* STOP SHIP if true */ 89 90 // Default Emergency Callback Mode exit timer 91 private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000; 92 93 static final String VM_COUNT_CDMA = "vm_count_key_cdma"; 94 private static final String VM_NUMBER_CDMA = "vm_number_key_cdma"; 95 private String mVmNumber = null; 96 97 static final int RESTART_ECM_TIMER = 0; // restart Ecm timer 98 static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer 99 100 // Instance Variables 101 CdmaCallTracker mCT; 102 CdmaServiceStateTracker mSST; 103 CdmaSubscriptionSourceManager mCdmaSSM; 104 ArrayList <CdmaMmiCode> mPendingMmis = new ArrayList<CdmaMmiCode>(); 105 RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager; 106 int mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN; 107 PhoneSubInfo mSubInfo; 108 EriManager mEriManager; 109 WakeLock mWakeLock; 110 111 // mEriFileLoadedRegistrants are informed after the ERI text has been loaded 112 private final RegistrantList mEriFileLoadedRegistrants = new RegistrantList(); 113 114 // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started 115 private final RegistrantList mEcmTimerResetRegistrants = new RegistrantList(); 116 117 // mEcmExitRespRegistrant is informed after the phone has been exited 118 //the emergency callback mode 119 //keep track of if phone is in emergency callback mode 120 private boolean mIsPhoneInEcmState; 121 private Registrant mEcmExitRespRegistrant; 122 protected String mImei; 123 protected String mImeiSv; 124 private String mEsn; 125 private String mMeid; 126 // string to define how the carrier specifies its own ota sp number 127 private String mCarrierOtaSpNumSchema; 128 129 // A runnable which is used to automatically exit from Ecm after a period of time. 130 private Runnable mExitEcmRunnable = new Runnable() { 131 @Override 132 public void run() { 133 exitEmergencyCallbackMode(); 134 } 135 }; 136 137 Registrant mPostDialHandler; 138 139 static String PROPERTY_CDMA_HOME_OPERATOR_NUMERIC = "ro.cdma.home.operator.numeric"; 140 141 // Constructors 142 public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) { 143 super("CDMA", notifier, context, ci, false); 144 initSstIcc(); 145 init(context, notifier); 146 } 147 148 public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, 149 boolean unitTestMode) { 150 super("CDMA", notifier, context, ci, unitTestMode); 151 initSstIcc(); 152 init(context, notifier); 153 } 154 155 protected void initSstIcc() { 156 mSST = new CdmaServiceStateTracker(this); 157 } 158 159 protected void init(Context context, PhoneNotifier notifier) { 160 mCi.setPhoneType(PhoneConstants.PHONE_TYPE_CDMA); 161 mCT = new CdmaCallTracker(this); 162 mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context, mCi, this, 163 EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); 164 mDcTracker = new DcTracker(this); 165 mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this); 166 mSubInfo = new PhoneSubInfo(this); 167 mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML); 168 169 mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); 170 mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); 171 mCi.registerForOn(this, EVENT_RADIO_ON, null); 172 mCi.setOnSuppServiceNotification(this, EVENT_SSN, null); 173 mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); 174 mCi.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null); 175 mCi.registerForExitEmergencyCallbackMode(this, EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE, 176 null); 177 178 PowerManager pm 179 = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 180 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,LOG_TAG); 181 182 //Change the system setting 183 SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE, 184 Integer.toString(PhoneConstants.PHONE_TYPE_CDMA)); 185 186 // This is needed to handle phone process crashes 187 String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); 188 mIsPhoneInEcmState = inEcm.equals("true"); 189 if (mIsPhoneInEcmState) { 190 // Send a message which will invoke handleExitEmergencyCallbackMode 191 mCi.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE)); 192 } 193 194 // get the string that specifies the carrier OTA Sp number 195 mCarrierOtaSpNumSchema = SystemProperties.get( 196 TelephonyProperties.PROPERTY_OTASP_NUM_SCHEMA,""); 197 198 // Sets operator alpha property by retrieving from build-time system property 199 String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha"); 200 setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, operatorAlpha); 201 202 // Sets operator numeric property by retrieving from build-time system property 203 String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC); 204 if (!TextUtils.isEmpty(operatorNumeric) && 205 (mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP) == null)) { 206 log("CDMAPhone: init set 'gsm.sim.operator.numeric' to operator='" + 207 operatorNumeric + "'"); 208 setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operatorNumeric); 209 } 210 211 // Sets iso country property by retrieving from build-time system property 212 setIsoCountryProperty(operatorNumeric); 213 214 // Sets current entry in the telephony carrier table 215 updateCurrentCarrierInProvider(operatorNumeric); 216 217 // Notify voicemails. 218 notifier.notifyMessageWaitingChanged(this); 219 } 220 221 @Override 222 public void dispose() { 223 synchronized(PhoneProxy.lockForRadioTechnologyChange) { 224 super.dispose(); 225 log("dispose"); 226 227 //Unregister from all former registered events 228 unregisterForRuimRecordEvents(); 229 mCi.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE 230 mCi.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE 231 mCi.unregisterForOn(this); //EVENT_RADIO_ON 232 mSST.unregisterForNetworkAttached(this); //EVENT_REGISTERED_TO_NETWORK 233 mCi.unSetOnSuppServiceNotification(this); 234 mCi.unregisterForExitEmergencyCallbackMode(this); 235 removeCallbacks(mExitEcmRunnable); 236 237 mPendingMmis.clear(); 238 239 //Force all referenced classes to unregister their former registered events 240 mCT.dispose(); 241 mDcTracker.dispose(); 242 mSST.dispose(); 243 mCdmaSSM.dispose(this); 244 mRuimPhoneBookInterfaceManager.dispose(); 245 mSubInfo.dispose(); 246 mEriManager.dispose(); 247 } 248 } 249 250 @Override 251 public void removeReferences() { 252 log("removeReferences"); 253 mRuimPhoneBookInterfaceManager = null; 254 mSubInfo = null; 255 mCT = null; 256 mSST = null; 257 mEriManager = null; 258 mExitEcmRunnable = null; 259 super.removeReferences(); 260 } 261 262 @Override 263 protected void finalize() { 264 if(DBG) Rlog.d(LOG_TAG, "CDMAPhone finalized"); 265 if (mWakeLock.isHeld()) { 266 Rlog.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing."); 267 mWakeLock.release(); 268 } 269 } 270 271 @Override 272 public ServiceState getServiceState() { 273 return mSST.mSS; 274 } 275 276 @Override 277 public CallTracker getCallTracker() { 278 return mCT; 279 } 280 281 @Override 282 public PhoneConstants.State getState() { 283 return mCT.mState; 284 } 285 286 @Override 287 public ServiceStateTracker getServiceStateTracker() { 288 return mSST; 289 } 290 291 @Override 292 public int getPhoneType() { 293 return PhoneConstants.PHONE_TYPE_CDMA; 294 } 295 296 @Override 297 public boolean canTransfer() { 298 Rlog.e(LOG_TAG, "canTransfer: not possible in CDMA"); 299 return false; 300 } 301 302 @Override 303 public CdmaCall getRingingCall() { 304 return mCT.mRingingCall; 305 } 306 307 @Override 308 public void setMute(boolean muted) { 309 mCT.setMute(muted); 310 } 311 312 @Override 313 public boolean getMute() { 314 return mCT.getMute(); 315 } 316 317 @Override 318 public void conference() { 319 // three way calls in CDMA will be handled by feature codes 320 Rlog.e(LOG_TAG, "conference: not possible in CDMA"); 321 } 322 323 @Override 324 public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { 325 mCi.setPreferredVoicePrivacy(enable, onComplete); 326 } 327 328 @Override 329 public void getEnhancedVoicePrivacy(Message onComplete) { 330 mCi.getPreferredVoicePrivacy(onComplete); 331 } 332 333 @Override 334 public void clearDisconnected() { 335 mCT.clearDisconnected(); 336 } 337 338 @Override 339 public DataActivityState getDataActivityState() { 340 DataActivityState ret = DataActivityState.NONE; 341 342 if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) { 343 344 switch (mDcTracker.getActivity()) { 345 case DATAIN: 346 ret = DataActivityState.DATAIN; 347 break; 348 349 case DATAOUT: 350 ret = DataActivityState.DATAOUT; 351 break; 352 353 case DATAINANDOUT: 354 ret = DataActivityState.DATAINANDOUT; 355 break; 356 357 case DORMANT: 358 ret = DataActivityState.DORMANT; 359 break; 360 361 default: 362 ret = DataActivityState.NONE; 363 break; 364 } 365 } 366 return ret; 367 } 368 369 @Override 370 public Connection 371 dial (String dialString) throws CallStateException { 372 // Need to make sure dialString gets parsed properly 373 String newDialString = PhoneNumberUtils.stripSeparators(dialString); 374 return mCT.dial(newDialString); 375 } 376 377 @Override 378 public Connection dial(String dialString, UUSInfo uusInfo) throws CallStateException { 379 throw new CallStateException("Sending UUS information NOT supported in CDMA!"); 380 } 381 382 @Override 383 public boolean 384 getMessageWaitingIndicator() { 385 return (getVoiceMessageCount() > 0); 386 } 387 388 @Override 389 public List<? extends MmiCode> 390 getPendingMmiCodes() { 391 return mPendingMmis; 392 } 393 394 @Override 395 public void registerForSuppServiceNotification( 396 Handler h, int what, Object obj) { 397 Rlog.e(LOG_TAG, "method registerForSuppServiceNotification is NOT supported in CDMA!"); 398 } 399 400 @Override 401 public CdmaCall getBackgroundCall() { 402 return mCT.mBackgroundCall; 403 } 404 405 @Override 406 public boolean handleInCallMmiCommands(String dialString) { 407 Rlog.e(LOG_TAG, "method handleInCallMmiCommands is NOT supported in CDMA!"); 408 return false; 409 } 410 411 boolean isInCall() { 412 CdmaCall.State foregroundCallState = getForegroundCall().getState(); 413 CdmaCall.State backgroundCallState = getBackgroundCall().getState(); 414 CdmaCall.State ringingCallState = getRingingCall().getState(); 415 416 return (foregroundCallState.isAlive() || backgroundCallState.isAlive() || ringingCallState 417 .isAlive()); 418 } 419 420 @Override 421 public void 422 setNetworkSelectionModeAutomatic(Message response) { 423 Rlog.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!"); 424 } 425 426 @Override 427 public void unregisterForSuppServiceNotification(Handler h) { 428 Rlog.e(LOG_TAG, "method unregisterForSuppServiceNotification is NOT supported in CDMA!"); 429 } 430 431 @Override 432 public void 433 acceptCall() throws CallStateException { 434 mCT.acceptCall(); 435 } 436 437 @Override 438 public void 439 rejectCall() throws CallStateException { 440 mCT.rejectCall(); 441 } 442 443 @Override 444 public void 445 switchHoldingAndActive() throws CallStateException { 446 mCT.switchWaitingOrHoldingAndActive(); 447 } 448 449 @Override 450 public String getIccSerialNumber() { 451 IccRecords r = mIccRecords.get(); 452 if (r == null) { 453 // to get ICCID form SIMRecords because it is on MF. 454 r = mUiccController.getIccRecords(UiccController.APP_FAM_3GPP); 455 } 456 return (r != null) ? r.getIccId() : null; 457 } 458 459 @Override 460 public String getLine1Number() { 461 return mSST.getMdnNumber(); 462 } 463 464 @Override 465 public String getCdmaPrlVersion(){ 466 return mSST.getPrlVersion(); 467 } 468 469 @Override 470 public String getCdmaMin() { 471 return mSST.getCdmaMin(); 472 } 473 474 @Override 475 public boolean isMinInfoReady() { 476 return mSST.isMinInfoReady(); 477 } 478 479 @Override 480 public void getCallWaiting(Message onComplete) { 481 mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete); 482 } 483 484 @Override 485 public void 486 setRadioPower(boolean power) { 487 mSST.setRadioPower(power); 488 } 489 490 @Override 491 public String getEsn() { 492 return mEsn; 493 } 494 495 @Override 496 public String getMeid() { 497 return mMeid; 498 } 499 500 //returns MEID or ESN in CDMA 501 @Override 502 public String getDeviceId() { 503 String id = getMeid(); 504 if ((id == null) || id.matches("^0*$")) { 505 Rlog.d(LOG_TAG, "getDeviceId(): MEID is not initialized use ESN"); 506 id = getEsn(); 507 } 508 return id; 509 } 510 511 @Override 512 public String getDeviceSvn() { 513 Rlog.d(LOG_TAG, "getDeviceSvn(): return 0"); 514 return "0"; 515 } 516 517 @Override 518 public String getSubscriberId() { 519 return mSST.getImsi(); 520 } 521 522 @Override 523 public String getGroupIdLevel1() { 524 Rlog.e(LOG_TAG, "GID1 is not available in CDMA"); 525 return null; 526 } 527 528 @Override 529 public String getImei() { 530 Rlog.e(LOG_TAG, "IMEI is not available in CDMA"); 531 return null; 532 } 533 534 @Override 535 public boolean canConference() { 536 Rlog.e(LOG_TAG, "canConference: not possible in CDMA"); 537 return false; 538 } 539 540 @Override 541 public CellLocation getCellLocation() { 542 CdmaCellLocation loc = mSST.mCellLoc; 543 544 int mode = Settings.Secure.getInt(getContext().getContentResolver(), 545 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); 546 if (mode == Settings.Secure.LOCATION_MODE_OFF) { 547 // clear lat/long values for location privacy 548 CdmaCellLocation privateLoc = new CdmaCellLocation(); 549 privateLoc.setCellLocationData(loc.getBaseStationId(), 550 CdmaCellLocation.INVALID_LAT_LONG, 551 CdmaCellLocation.INVALID_LAT_LONG, 552 loc.getSystemId(), loc.getNetworkId()); 553 loc = privateLoc; 554 } 555 return loc; 556 } 557 558 @Override 559 public CdmaCall getForegroundCall() { 560 return mCT.mForegroundCall; 561 } 562 563 @Override 564 public void 565 selectNetworkManually(OperatorInfo network, 566 Message response) { 567 Rlog.e(LOG_TAG, "selectNetworkManually: not possible in CDMA"); 568 } 569 570 @Override 571 public void setOnPostDialCharacter(Handler h, int what, Object obj) { 572 mPostDialHandler = new Registrant(h, what, obj); 573 } 574 575 @Override 576 public boolean handlePinMmi(String dialString) { 577 CdmaMmiCode mmi = CdmaMmiCode.newFromDialString(dialString, this, mUiccApplication.get()); 578 579 if (mmi == null) { 580 Rlog.e(LOG_TAG, "Mmi is NULL!"); 581 return false; 582 } else if (mmi.isPinPukCommand()) { 583 mPendingMmis.add(mmi); 584 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 585 mmi.processCode(); 586 return true; 587 } 588 Rlog.e(LOG_TAG, "Unrecognized mmi!"); 589 return false; 590 } 591 592 /** 593 * Removes the given MMI from the pending list and notifies registrants that 594 * it is complete. 595 * 596 * @param mmi MMI that is done 597 */ 598 void onMMIDone(CdmaMmiCode mmi) { 599 /* 600 * Only notify complete if it's on the pending list. Otherwise, it's 601 * already been handled (eg, previously canceled). 602 */ 603 if (mPendingMmis.remove(mmi)) { 604 mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 605 } 606 } 607 608 @Override 609 public void setLine1Number(String alphaTag, String number, Message onComplete) { 610 Rlog.e(LOG_TAG, "setLine1Number: not possible in CDMA"); 611 } 612 613 @Override 614 public void setCallWaiting(boolean enable, Message onComplete) { 615 Rlog.e(LOG_TAG, "method setCallWaiting is NOT supported in CDMA!"); 616 } 617 618 @Override 619 public void updateServiceLocation() { 620 mSST.enableSingleLocationUpdate(); 621 } 622 623 @Override 624 public void setDataRoamingEnabled(boolean enable) { 625 mDcTracker.setDataOnRoamingEnabled(enable); 626 } 627 628 @Override 629 public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) { 630 mCi.registerForCdmaOtaProvision(h, what, obj); 631 } 632 633 @Override 634 public void unregisterForCdmaOtaStatusChange(Handler h) { 635 mCi.unregisterForCdmaOtaProvision(h); 636 } 637 638 @Override 639 public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) { 640 mSST.registerForSubscriptionInfoReady(h, what, obj); 641 } 642 643 @Override 644 public void unregisterForSubscriptionInfoReady(Handler h) { 645 mSST.unregisterForSubscriptionInfoReady(h); 646 } 647 648 @Override 649 public void setOnEcbModeExitResponse(Handler h, int what, Object obj) { 650 mEcmExitRespRegistrant = new Registrant (h, what, obj); 651 } 652 653 @Override 654 public void unsetOnEcbModeExitResponse(Handler h) { 655 mEcmExitRespRegistrant.clear(); 656 } 657 658 @Override 659 public void registerForCallWaiting(Handler h, int what, Object obj) { 660 mCT.registerForCallWaiting(h, what, obj); 661 } 662 663 @Override 664 public void unregisterForCallWaiting(Handler h) { 665 mCT.unregisterForCallWaiting(h); 666 } 667 668 @Override 669 public void 670 getNeighboringCids(Message response) { 671 /* 672 * This is currently not implemented. At least as of June 673 * 2009, there is no neighbor cell information available for 674 * CDMA because some party is resisting making this 675 * information readily available. Consequently, calling this 676 * function can have no useful effect. This situation may 677 * (and hopefully will) change in the future. 678 */ 679 if (response != null) { 680 CommandException ce = new CommandException( 681 CommandException.Error.REQUEST_NOT_SUPPORTED); 682 AsyncResult.forMessage(response).exception = ce; 683 response.sendToTarget(); 684 } 685 } 686 687 @Override 688 public PhoneConstants.DataState getDataConnectionState(String apnType) { 689 PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED; 690 691 if (mSST == null) { 692 // Radio Technology Change is ongoning, dispose() and removeReferences() have 693 // already been called 694 695 ret = PhoneConstants.DataState.DISCONNECTED; 696 } else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) { 697 // If we're out of service, open TCP sockets may still work 698 // but no data will flow 699 ret = PhoneConstants.DataState.DISCONNECTED; 700 } else if (mDcTracker.isApnTypeEnabled(apnType) == false || 701 mDcTracker.isApnTypeActive(apnType) == false) { 702 ret = PhoneConstants.DataState.DISCONNECTED; 703 } else { 704 switch (mDcTracker.getState(apnType)) { 705 case RETRYING: 706 case FAILED: 707 case IDLE: 708 ret = PhoneConstants.DataState.DISCONNECTED; 709 break; 710 711 case CONNECTED: 712 case DISCONNECTING: 713 if ( mCT.mState != PhoneConstants.State.IDLE 714 && !mSST.isConcurrentVoiceAndDataAllowed()) { 715 ret = PhoneConstants.DataState.SUSPENDED; 716 } else { 717 ret = PhoneConstants.DataState.CONNECTED; 718 } 719 break; 720 721 case CONNECTING: 722 case SCANNING: 723 ret = PhoneConstants.DataState.CONNECTING; 724 break; 725 } 726 } 727 728 log("getDataConnectionState apnType=" + apnType + " ret=" + ret); 729 return ret; 730 } 731 732 @Override 733 public void sendUssdResponse(String ussdMessge) { 734 Rlog.e(LOG_TAG, "sendUssdResponse: not possible in CDMA"); 735 } 736 737 @Override 738 public void sendDtmf(char c) { 739 if (!PhoneNumberUtils.is12Key(c)) { 740 Rlog.e(LOG_TAG, 741 "sendDtmf called with invalid character '" + c + "'"); 742 } else { 743 if (mCT.mState == PhoneConstants.State.OFFHOOK) { 744 mCi.sendDtmf(c, null); 745 } 746 } 747 } 748 749 @Override 750 public void startDtmf(char c) { 751 if (!PhoneNumberUtils.is12Key(c)) { 752 Rlog.e(LOG_TAG, 753 "startDtmf called with invalid character '" + c + "'"); 754 } else { 755 mCi.startDtmf(c, null); 756 } 757 } 758 759 @Override 760 public void stopDtmf() { 761 mCi.stopDtmf(null); 762 } 763 764 @Override 765 public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) { 766 boolean check = true; 767 for (int itr = 0;itr < dtmfString.length(); itr++) { 768 if (!PhoneNumberUtils.is12Key(dtmfString.charAt(itr))) { 769 Rlog.e(LOG_TAG, 770 "sendDtmf called with invalid character '" + dtmfString.charAt(itr)+ "'"); 771 check = false; 772 break; 773 } 774 } 775 if ((mCT.mState == PhoneConstants.State.OFFHOOK)&&(check)) { 776 mCi.sendBurstDtmf(dtmfString, on, off, onComplete); 777 } 778 } 779 780 @Override 781 public void getAvailableNetworks(Message response) { 782 Rlog.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA"); 783 } 784 785 @Override 786 public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) { 787 Rlog.e(LOG_TAG, "setOutgoingCallerIdDisplay: not possible in CDMA"); 788 } 789 790 @Override 791 public void enableLocationUpdates() { 792 mSST.enableLocationUpdates(); 793 } 794 795 @Override 796 public void disableLocationUpdates() { 797 mSST.disableLocationUpdates(); 798 } 799 800 @Override 801 public void getDataCallList(Message response) { 802 mCi.getDataCallList(response); 803 } 804 805 @Override 806 public boolean getDataRoamingEnabled() { 807 return mDcTracker.getDataOnRoamingEnabled(); 808 } 809 810 @Override 811 public void setVoiceMailNumber(String alphaTag, 812 String voiceMailNumber, 813 Message onComplete) { 814 Message resp; 815 mVmNumber = voiceMailNumber; 816 resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete); 817 IccRecords r = mIccRecords.get(); 818 if (r != null) { 819 r.setVoiceMailNumber(alphaTag, mVmNumber, resp); 820 } 821 } 822 823 @Override 824 public String getVoiceMailNumber() { 825 String number = null; 826 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); 827 // TODO: The default value of voicemail number should be read from a system property 828 829 // Read platform settings for dynamic voicemail number 830 if (getContext().getResources().getBoolean(com.android.internal 831 .R.bool.config_telephony_use_own_number_for_voicemail)) { 832 number = sp.getString(VM_NUMBER_CDMA, getLine1Number()); 833 } else { 834 number = sp.getString(VM_NUMBER_CDMA, "*86"); 835 } 836 return number; 837 } 838 839 /* Returns Number of Voicemails 840 * @hide 841 */ 842 @Override 843 public int getVoiceMessageCount() { 844 IccRecords r = mIccRecords.get(); 845 int voicemailCount = (r != null) ? r.getVoiceMessageCount() : 0; 846 // If mRuimRecords.getVoiceMessageCount returns zero, then there is possibility 847 // that phone was power cycled and would have lost the voicemail count. 848 // So get the count from preferences. 849 if (voicemailCount == 0) { 850 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); 851 voicemailCount = sp.getInt(VM_COUNT_CDMA, 0); 852 } 853 return voicemailCount; 854 } 855 856 @Override 857 public String getVoiceMailAlphaTag() { 858 // TODO: Where can we get this value has to be clarified with QC. 859 String ret = "";//TODO: Remove = "", if we know where to get this value. 860 861 //ret = mSIMRecords.getVoiceMailAlphaTag(); 862 863 if (ret == null || ret.length() == 0) { 864 return mContext.getText( 865 com.android.internal.R.string.defaultVoiceMailAlphaTag).toString(); 866 } 867 868 return ret; 869 } 870 871 @Override 872 public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { 873 Rlog.e(LOG_TAG, "getCallForwardingOption: not possible in CDMA"); 874 } 875 876 @Override 877 public void setCallForwardingOption(int commandInterfaceCFAction, 878 int commandInterfaceCFReason, 879 String dialingNumber, 880 int timerSeconds, 881 Message onComplete) { 882 Rlog.e(LOG_TAG, "setCallForwardingOption: not possible in CDMA"); 883 } 884 885 @Override 886 public void 887 getOutgoingCallerIdDisplay(Message onComplete) { 888 Rlog.e(LOG_TAG, "getOutgoingCallerIdDisplay: not possible in CDMA"); 889 } 890 891 @Override 892 public boolean 893 getCallForwardingIndicator() { 894 Rlog.e(LOG_TAG, "getCallForwardingIndicator: not possible in CDMA"); 895 return false; 896 } 897 898 @Override 899 public void explicitCallTransfer() { 900 Rlog.e(LOG_TAG, "explicitCallTransfer: not possible in CDMA"); 901 } 902 903 @Override 904 public String getLine1AlphaTag() { 905 Rlog.e(LOG_TAG, "getLine1AlphaTag: not possible in CDMA"); 906 return null; 907 } 908 909 /** 910 * Notify any interested party of a Phone state change 911 * {@link com.android.internal.telephony.PhoneConstants.State} 912 */ 913 /*package*/ void notifyPhoneStateChanged() { 914 mNotifier.notifyPhoneState(this); 915 } 916 917 /** 918 * Notify registrants of a change in the call state. This notifies changes in 919 * {@link com.android.internal.telephony.Call.State}. Use this when changes 920 * in the precise call state are needed, else use notifyPhoneStateChanged. 921 */ 922 /*package*/ void notifyPreciseCallStateChanged() { 923 /* we'd love it if this was package-scoped*/ 924 super.notifyPreciseCallStateChangedP(); 925 } 926 927 void notifyServiceStateChanged(ServiceState ss) { 928 super.notifyServiceStateChangedP(ss); 929 } 930 931 void notifyLocationChanged() { 932 mNotifier.notifyCellLocation(this); 933 } 934 935 /*package*/ void notifyNewRingingConnection(Connection c) { 936 /* we'd love it if this was package-scoped*/ 937 super.notifyNewRingingConnectionP(c); 938 } 939 940 /*package*/ void notifyDisconnect(Connection cn) { 941 mDisconnectRegistrants.notifyResult(cn); 942 } 943 944 void notifyUnknownConnection() { 945 mUnknownConnectionRegistrants.notifyResult(this); 946 } 947 948 @Override 949 public boolean isInEmergencyCall() { 950 return mCT.isInEmergencyCall(); 951 } 952 953 @Override 954 public boolean isInEcm() { 955 return mIsPhoneInEcmState; 956 } 957 958 void sendEmergencyCallbackModeChange(){ 959 //Send an Intent 960 Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 961 intent.putExtra(PhoneConstants.PHONE_IN_ECM_STATE, mIsPhoneInEcmState); 962 ActivityManagerNative.broadcastStickyIntent(intent,null,UserHandle.USER_ALL); 963 if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallbackModeChange"); 964 } 965 966 @Override 967 public void exitEmergencyCallbackMode() { 968 if (mWakeLock.isHeld()) { 969 mWakeLock.release(); 970 } 971 // Send a message which will invoke handleExitEmergencyCallbackMode 972 mCi.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE)); 973 } 974 975 private void handleEnterEmergencyCallbackMode(Message msg) { 976 if (DBG) { 977 Rlog.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= " 978 + mIsPhoneInEcmState); 979 } 980 // if phone is not in Ecm mode, and it's changed to Ecm mode 981 if (mIsPhoneInEcmState == false) { 982 mIsPhoneInEcmState = true; 983 // notify change 984 sendEmergencyCallbackModeChange(); 985 setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true"); 986 987 // Post this runnable so we will automatically exit 988 // if no one invokes exitEmergencyCallbackMode() directly. 989 long delayInMillis = SystemProperties.getLong( 990 TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE); 991 postDelayed(mExitEcmRunnable, delayInMillis); 992 // We don't want to go to sleep while in Ecm 993 mWakeLock.acquire(); 994 } 995 } 996 997 private void handleExitEmergencyCallbackMode(Message msg) { 998 AsyncResult ar = (AsyncResult)msg.obj; 999 if (DBG) { 1000 Rlog.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , mIsPhoneInEcmState " 1001 + ar.exception + mIsPhoneInEcmState); 1002 } 1003 // Remove pending exit Ecm runnable, if any 1004 removeCallbacks(mExitEcmRunnable); 1005 1006 if (mEcmExitRespRegistrant != null) { 1007 mEcmExitRespRegistrant.notifyRegistrant(ar); 1008 } 1009 // if exiting ecm success 1010 if (ar.exception == null) { 1011 if (mIsPhoneInEcmState) { 1012 mIsPhoneInEcmState = false; 1013 setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false"); 1014 } 1015 // send an Intent 1016 sendEmergencyCallbackModeChange(); 1017 // Re-initiate data connection 1018 mDcTracker.setInternalDataEnabled(true); 1019 } 1020 } 1021 1022 /** 1023 * Handle to cancel or restart Ecm timer in emergency call back mode 1024 * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled; 1025 * otherwise, restart Ecm timer and notify apps the timer is restarted. 1026 */ 1027 void handleTimerInEmergencyCallbackMode(int action) { 1028 switch(action) { 1029 case CANCEL_ECM_TIMER: 1030 removeCallbacks(mExitEcmRunnable); 1031 mEcmTimerResetRegistrants.notifyResult(Boolean.TRUE); 1032 break; 1033 case RESTART_ECM_TIMER: 1034 long delayInMillis = SystemProperties.getLong( 1035 TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE); 1036 postDelayed(mExitEcmRunnable, delayInMillis); 1037 mEcmTimerResetRegistrants.notifyResult(Boolean.FALSE); 1038 break; 1039 default: 1040 Rlog.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action); 1041 } 1042 } 1043 1044 /** 1045 * Registration point for Ecm timer reset 1046 * @param h handler to notify 1047 * @param what User-defined message code 1048 * @param obj placed in Message.obj 1049 */ 1050 @Override 1051 public void registerForEcmTimerReset(Handler h, int what, Object obj) { 1052 mEcmTimerResetRegistrants.addUnique(h, what, obj); 1053 } 1054 1055 @Override 1056 public void unregisterForEcmTimerReset(Handler h) { 1057 mEcmTimerResetRegistrants.remove(h); 1058 } 1059 1060 @Override 1061 public void handleMessage(Message msg) { 1062 AsyncResult ar; 1063 Message onComplete; 1064 1065 if (!mIsTheCurrentActivePhone) { 1066 Rlog.e(LOG_TAG, "Received message " + msg + 1067 "[" + msg.what + "] while being destroyed. Ignoring."); 1068 return; 1069 } 1070 switch(msg.what) { 1071 case EVENT_RADIO_AVAILABLE: { 1072 mCi.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE)); 1073 1074 mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE)); 1075 } 1076 break; 1077 1078 case EVENT_GET_BASEBAND_VERSION_DONE:{ 1079 ar = (AsyncResult)msg.obj; 1080 1081 if (ar.exception != null) { 1082 break; 1083 } 1084 1085 if (DBG) Rlog.d(LOG_TAG, "Baseband version: " + ar.result); 1086 setSystemProperty(TelephonyProperties.PROPERTY_BASEBAND_VERSION, (String)ar.result); 1087 } 1088 break; 1089 1090 case EVENT_GET_DEVICE_IDENTITY_DONE:{ 1091 ar = (AsyncResult)msg.obj; 1092 1093 if (ar.exception != null) { 1094 break; 1095 } 1096 String[] respId = (String[])ar.result; 1097 mImei = respId[0]; 1098 mImeiSv = respId[1]; 1099 mEsn = respId[2]; 1100 mMeid = respId[3]; 1101 } 1102 break; 1103 1104 case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{ 1105 handleEnterEmergencyCallbackMode(msg); 1106 } 1107 break; 1108 1109 case EVENT_ICC_RECORD_EVENTS: 1110 ar = (AsyncResult)msg.obj; 1111 processIccRecordEvents((Integer)ar.result); 1112 break; 1113 1114 case EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{ 1115 handleExitEmergencyCallbackMode(msg); 1116 } 1117 break; 1118 1119 case EVENT_RUIM_RECORDS_LOADED:{ 1120 Rlog.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received"); 1121 updateCurrentCarrierInProvider(); 1122 } 1123 break; 1124 1125 case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{ 1126 Rlog.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); 1127 } 1128 break; 1129 1130 case EVENT_RADIO_ON:{ 1131 Rlog.d(LOG_TAG, "Event EVENT_RADIO_ON Received"); 1132 handleCdmaSubscriptionSource(mCdmaSSM.getCdmaSubscriptionSource()); 1133 } 1134 break; 1135 1136 case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:{ 1137 Rlog.d(LOG_TAG, "EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED"); 1138 handleCdmaSubscriptionSource(mCdmaSSM.getCdmaSubscriptionSource()); 1139 } 1140 break; 1141 1142 case EVENT_SSN:{ 1143 Rlog.d(LOG_TAG, "Event EVENT_SSN Received"); 1144 } 1145 break; 1146 1147 case EVENT_REGISTERED_TO_NETWORK:{ 1148 Rlog.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received"); 1149 } 1150 break; 1151 1152 case EVENT_NV_READY:{ 1153 Rlog.d(LOG_TAG, "Event EVENT_NV_READY Received"); 1154 prepareEri(); 1155 } 1156 break; 1157 1158 case EVENT_SET_VM_NUMBER_DONE:{ 1159 ar = (AsyncResult)msg.obj; 1160 if (IccException.class.isInstance(ar.exception)) { 1161 storeVoiceMailNumber(mVmNumber); 1162 ar.exception = null; 1163 } 1164 onComplete = (Message) ar.userObj; 1165 if (onComplete != null) { 1166 AsyncResult.forMessage(onComplete, ar.result, ar.exception); 1167 onComplete.sendToTarget(); 1168 } 1169 } 1170 break; 1171 1172 default:{ 1173 super.handleMessage(msg); 1174 } 1175 } 1176 } 1177 1178 @Override 1179 protected void onUpdateIccAvailability() { 1180 if (mUiccController == null ) { 1181 return; 1182 } 1183 1184 UiccCardApplication newUiccApplication = 1185 mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP2); 1186 1187 if (newUiccApplication == null) { 1188 log("can't find 3GPP2 application; trying APP_FAM_3GPP"); 1189 newUiccApplication = mUiccController 1190 .getUiccCardApplication(UiccController.APP_FAM_3GPP); 1191 } 1192 1193 UiccCardApplication app = mUiccApplication.get(); 1194 if (app != newUiccApplication) { 1195 if (app != null) { 1196 log("Removing stale icc objects."); 1197 if (mIccRecords.get() != null) { 1198 unregisterForRuimRecordEvents(); 1199 mRuimPhoneBookInterfaceManager.updateIccRecords(null); 1200 } 1201 mIccRecords.set(null); 1202 mUiccApplication.set(null); 1203 } 1204 if (newUiccApplication != null) { 1205 log("New Uicc application found"); 1206 mUiccApplication.set(newUiccApplication); 1207 mIccRecords.set(newUiccApplication.getIccRecords()); 1208 registerForRuimRecordEvents(); 1209 mRuimPhoneBookInterfaceManager.updateIccRecords(mIccRecords.get()); 1210 } 1211 } 1212 } 1213 1214 private void processIccRecordEvents(int eventCode) { 1215 switch (eventCode) { 1216 case RuimRecords.EVENT_MWI: 1217 notifyMessageWaitingIndicator(); 1218 break; 1219 1220 default: 1221 Rlog.e(LOG_TAG,"Unknown icc records event code " + eventCode); 1222 break; 1223 } 1224 } 1225 1226 /** 1227 * Handles the call to get the subscription source 1228 * 1229 * @param newSubscriptionSource holds the new CDMA subscription source value 1230 */ 1231 private void handleCdmaSubscriptionSource(int newSubscriptionSource) { 1232 if (newSubscriptionSource != mCdmaSubscriptionSource) { 1233 mCdmaSubscriptionSource = newSubscriptionSource; 1234 if (newSubscriptionSource == CDMA_SUBSCRIPTION_NV) { 1235 // NV is ready when subscription source is NV 1236 sendMessage(obtainMessage(EVENT_NV_READY)); 1237 } 1238 } 1239 } 1240 1241 /** 1242 * Retrieves the PhoneSubInfo of the CDMAPhone 1243 */ 1244 @Override 1245 public PhoneSubInfo getPhoneSubInfo() { 1246 return mSubInfo; 1247 } 1248 1249 /** 1250 * Retrieves the IccPhoneBookInterfaceManager of the CDMAPhone 1251 */ 1252 @Override 1253 public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager() { 1254 return mRuimPhoneBookInterfaceManager; 1255 } 1256 1257 public void registerForEriFileLoaded(Handler h, int what, Object obj) { 1258 Registrant r = new Registrant (h, what, obj); 1259 mEriFileLoadedRegistrants.add(r); 1260 } 1261 1262 public void unregisterForEriFileLoaded(Handler h) { 1263 mEriFileLoadedRegistrants.remove(h); 1264 } 1265 1266 // override for allowing access from other classes of this package 1267 /** 1268 * {@inheritDoc} 1269 */ 1270 @Override 1271 public final void setSystemProperty(String property, String value) { 1272 super.setSystemProperty(property, value); 1273 } 1274 1275 /** 1276 * Activate or deactivate cell broadcast SMS. 1277 * 1278 * @param activate 0 = activate, 1 = deactivate 1279 * @param response Callback message is empty on completion 1280 */ 1281 @Override 1282 public void activateCellBroadcastSms(int activate, Message response) { 1283 Rlog.e(LOG_TAG, "[CDMAPhone] activateCellBroadcastSms() is obsolete; use SmsManager"); 1284 response.sendToTarget(); 1285 } 1286 1287 /** 1288 * Query the current configuration of cdma cell broadcast SMS. 1289 * 1290 * @param response Callback message is empty on completion 1291 */ 1292 @Override 1293 public void getCellBroadcastSmsConfig(Message response) { 1294 Rlog.e(LOG_TAG, "[CDMAPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager"); 1295 response.sendToTarget(); 1296 } 1297 1298 /** 1299 * Configure cdma cell broadcast SMS. 1300 * 1301 * @param response Callback message is empty on completion 1302 */ 1303 @Override 1304 public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) { 1305 Rlog.e(LOG_TAG, "[CDMAPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager"); 1306 response.sendToTarget(); 1307 } 1308 1309 /** 1310 * Returns true if OTA Service Provisioning needs to be performed. 1311 */ 1312 @Override 1313 public boolean needsOtaServiceProvisioning() { 1314 return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED; 1315 } 1316 1317 private static final String IS683A_FEATURE_CODE = "*228"; 1318 private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4; 1319 private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2; 1320 private static final int IS683A_SYS_SEL_CODE_OFFSET = 4; 1321 1322 private static final int IS683_CONST_800MHZ_A_BAND = 0; 1323 private static final int IS683_CONST_800MHZ_B_BAND = 1; 1324 private static final int IS683_CONST_1900MHZ_A_BLOCK = 2; 1325 private static final int IS683_CONST_1900MHZ_B_BLOCK = 3; 1326 private static final int IS683_CONST_1900MHZ_C_BLOCK = 4; 1327 private static final int IS683_CONST_1900MHZ_D_BLOCK = 5; 1328 private static final int IS683_CONST_1900MHZ_E_BLOCK = 6; 1329 private static final int IS683_CONST_1900MHZ_F_BLOCK = 7; 1330 private static final int INVALID_SYSTEM_SELECTION_CODE = -1; 1331 1332 private static boolean isIs683OtaSpDialStr(String dialStr) { 1333 int sysSelCodeInt; 1334 boolean isOtaspDialString = false; 1335 int dialStrLen = dialStr.length(); 1336 1337 if (dialStrLen == IS683A_FEATURE_CODE_NUM_DIGITS) { 1338 if (dialStr.equals(IS683A_FEATURE_CODE)) { 1339 isOtaspDialString = true; 1340 } 1341 } else { 1342 sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr); 1343 switch (sysSelCodeInt) { 1344 case IS683_CONST_800MHZ_A_BAND: 1345 case IS683_CONST_800MHZ_B_BAND: 1346 case IS683_CONST_1900MHZ_A_BLOCK: 1347 case IS683_CONST_1900MHZ_B_BLOCK: 1348 case IS683_CONST_1900MHZ_C_BLOCK: 1349 case IS683_CONST_1900MHZ_D_BLOCK: 1350 case IS683_CONST_1900MHZ_E_BLOCK: 1351 case IS683_CONST_1900MHZ_F_BLOCK: 1352 isOtaspDialString = true; 1353 break; 1354 default: 1355 break; 1356 } 1357 } 1358 return isOtaspDialString; 1359 } 1360 /** 1361 * This function extracts the system selection code from the dial string. 1362 */ 1363 private static int extractSelCodeFromOtaSpNum(String dialStr) { 1364 int dialStrLen = dialStr.length(); 1365 int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE; 1366 1367 if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE, 1368 0, IS683A_FEATURE_CODE_NUM_DIGITS)) && 1369 (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS + 1370 IS683A_SYS_SEL_CODE_NUM_DIGITS))) { 1371 // Since we checked the condition above, the system selection code 1372 // extracted from dialStr will not cause any exception 1373 sysSelCodeInt = Integer.parseInt ( 1374 dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS, 1375 IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS)); 1376 } 1377 if (DBG) Rlog.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt); 1378 return sysSelCodeInt; 1379 } 1380 1381 /** 1382 * This function checks if the system selection code extracted from 1383 * the dial string "sysSelCodeInt' is the system selection code specified 1384 * in the carrier ota sp number schema "sch". 1385 */ 1386 private static boolean 1387 checkOtaSpNumBasedOnSysSelCode (int sysSelCodeInt, String sch[]) { 1388 boolean isOtaSpNum = false; 1389 try { 1390 // Get how many number of system selection code ranges 1391 int selRc = Integer.parseInt(sch[1]); 1392 for (int i = 0; i < selRc; i++) { 1393 if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) { 1394 int selMin = Integer.parseInt(sch[i+2]); 1395 int selMax = Integer.parseInt(sch[i+3]); 1396 // Check if the selection code extracted from the dial string falls 1397 // within any of the range pairs specified in the schema. 1398 if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) { 1399 isOtaSpNum = true; 1400 break; 1401 } 1402 } 1403 } 1404 } catch (NumberFormatException ex) { 1405 // If the carrier ota sp number schema is not correct, we still allow dial 1406 // and only log the error: 1407 Rlog.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex); 1408 } 1409 return isOtaSpNum; 1410 } 1411 1412 // Define the pattern/format for carrier specified OTASP number schema. 1413 // It separates by comma and/or whitespace. 1414 private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+"); 1415 1416 /** 1417 * The following function checks if a dial string is a carrier specified 1418 * OTASP number or not by checking against the OTASP number schema stored 1419 * in PROPERTY_OTASP_NUM_SCHEMA. 1420 * 1421 * Currently, there are 2 schemas for carriers to specify the OTASP number: 1422 * 1) Use system selection code: 1423 * The schema is: 1424 * SELC,the # of code pairs,min1,max1,min2,max2,... 1425 * e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of 1426 * selection codes, and they are {10,20}, {30,40} and {60,70} respectively. 1427 * 1428 * 2) Use feature code: 1429 * The schema is: 1430 * "FC,length of feature code,feature code". 1431 * e.g "FC,2,*2" indicates that the length of the feature code is 2, 1432 * and the code itself is "*2". 1433 */ 1434 private boolean isCarrierOtaSpNum(String dialStr) { 1435 boolean isOtaSpNum = false; 1436 int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr); 1437 if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) { 1438 return isOtaSpNum; 1439 } 1440 // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA: 1441 if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) { 1442 Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema); 1443 if (DBG) { 1444 Rlog.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema); 1445 } 1446 1447 if (m.find()) { 1448 String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema); 1449 // If carrier uses system selection code mechanism 1450 if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) { 1451 if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) { 1452 isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch); 1453 } else { 1454 if (DBG) { 1455 Rlog.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid"); 1456 } 1457 } 1458 } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) { 1459 int fcLen = Integer.parseInt(sch[1]); 1460 String fc = sch[2]; 1461 if (dialStr.regionMatches(0,fc,0,fcLen)) { 1462 isOtaSpNum = true; 1463 } else { 1464 if (DBG) Rlog.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number"); 1465 } 1466 } else { 1467 if (DBG) { 1468 Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]); 1469 } 1470 } 1471 } else { 1472 if (DBG) { 1473 Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" + 1474 mCarrierOtaSpNumSchema); 1475 } 1476 } 1477 } else { 1478 if (DBG) Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty"); 1479 } 1480 return isOtaSpNum; 1481 } 1482 1483 /** 1484 * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier 1485 * OTASP dial string. 1486 * 1487 * @param dialStr the number to look up. 1488 * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string 1489 */ 1490 @Override 1491 public boolean isOtaSpNumber(String dialStr){ 1492 boolean isOtaSpNum = false; 1493 String dialableStr = PhoneNumberUtils.extractNetworkPortionAlt(dialStr); 1494 if (dialableStr != null) { 1495 isOtaSpNum = isIs683OtaSpDialStr(dialableStr); 1496 if (isOtaSpNum == false) { 1497 isOtaSpNum = isCarrierOtaSpNum(dialableStr); 1498 } 1499 } 1500 if (DBG) Rlog.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum); 1501 return isOtaSpNum; 1502 } 1503 1504 @Override 1505 public int getCdmaEriIconIndex() { 1506 return getServiceState().getCdmaEriIconIndex(); 1507 } 1508 1509 /** 1510 * Returns the CDMA ERI icon mode, 1511 * 0 - ON 1512 * 1 - FLASHING 1513 */ 1514 @Override 1515 public int getCdmaEriIconMode() { 1516 return getServiceState().getCdmaEriIconMode(); 1517 } 1518 1519 /** 1520 * Returns the CDMA ERI text, 1521 */ 1522 @Override 1523 public String getCdmaEriText() { 1524 int roamInd = getServiceState().getCdmaRoamingIndicator(); 1525 int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator(); 1526 return mEriManager.getCdmaEriText(roamInd, defRoamInd); 1527 } 1528 1529 /** 1530 * Store the voicemail number in preferences 1531 */ 1532 private void storeVoiceMailNumber(String number) { 1533 // Update the preference value of voicemail number 1534 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); 1535 SharedPreferences.Editor editor = sp.edit(); 1536 editor.putString(VM_NUMBER_CDMA, number); 1537 editor.apply(); 1538 } 1539 1540 /** 1541 * Sets PROPERTY_ICC_OPERATOR_ISO_COUNTRY property 1542 * 1543 */ 1544 private void setIsoCountryProperty(String operatorNumeric) { 1545 if (TextUtils.isEmpty(operatorNumeric)) { 1546 setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, ""); 1547 } else { 1548 String iso = ""; 1549 try { 1550 iso = MccTable.countryCodeForMcc(Integer.parseInt( 1551 operatorNumeric.substring(0,3))); 1552 } catch (NumberFormatException ex) { 1553 Rlog.w(LOG_TAG, "countryCodeForMcc error" + ex); 1554 } catch (StringIndexOutOfBoundsException ex) { 1555 Rlog.w(LOG_TAG, "countryCodeForMcc error" + ex); 1556 } 1557 1558 setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, iso); 1559 } 1560 } 1561 1562 /** 1563 * Sets the "current" field in the telephony provider according to the 1564 * build-time operator numeric property 1565 * 1566 * @return true for success; false otherwise. 1567 */ 1568 boolean updateCurrentCarrierInProvider(String operatorNumeric) { 1569 if (!TextUtils.isEmpty(operatorNumeric)) { 1570 try { 1571 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"); 1572 ContentValues map = new ContentValues(); 1573 map.put(Telephony.Carriers.NUMERIC, operatorNumeric); 1574 log("updateCurrentCarrierInProvider from system: numeric=" + operatorNumeric); 1575 getContext().getContentResolver().insert(uri, map); 1576 1577 // Updates MCC MNC device configuration information 1578 MccTable.updateMccMncConfiguration(mContext, operatorNumeric); 1579 1580 return true; 1581 } catch (SQLException e) { 1582 Rlog.e(LOG_TAG, "Can't store current operator", e); 1583 } 1584 } 1585 return false; 1586 } 1587 1588 /** 1589 * Sets the "current" field in the telephony provider according to the SIM's operator. 1590 * Implemented in {@link CDMALTEPhone} for CDMA/LTE devices. 1591 * 1592 * @return true for success; false otherwise. 1593 */ 1594 boolean updateCurrentCarrierInProvider() { 1595 return true; 1596 } 1597 1598 public void prepareEri() { 1599 mEriManager.loadEriFile(); 1600 if(mEriManager.isEriFileLoaded()) { 1601 // when the ERI file is loaded 1602 log("ERI read, notify registrants"); 1603 mEriFileLoadedRegistrants.notifyRegistrants(); 1604 } 1605 } 1606 1607 public boolean isEriFileLoaded() { 1608 return mEriManager.isEriFileLoaded(); 1609 } 1610 1611 protected void registerForRuimRecordEvents() { 1612 IccRecords r = mIccRecords.get(); 1613 if (r == null) { 1614 return; 1615 } 1616 r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null); 1617 r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null); 1618 } 1619 1620 protected void unregisterForRuimRecordEvents() { 1621 IccRecords r = mIccRecords.get(); 1622 if (r == null) { 1623 return; 1624 } 1625 r.unregisterForRecordsEvents(this); 1626 r.unregisterForRecordsLoaded(this); 1627 } 1628 1629 protected void log(String s) { 1630 if (DBG) 1631 Rlog.d(LOG_TAG, s); 1632 } 1633 1634 @Override 1635 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1636 pw.println("CDMAPhone extends:"); 1637 super.dump(fd, pw, args); 1638 pw.println(" mVmNumber=" + mVmNumber); 1639 pw.println(" mCT=" + mCT); 1640 pw.println(" mSST=" + mSST); 1641 pw.println(" mCdmaSSM=" + mCdmaSSM); 1642 pw.println(" mPendingMmis=" + mPendingMmis); 1643 pw.println(" mRuimPhoneBookInterfaceManager=" + mRuimPhoneBookInterfaceManager); 1644 pw.println(" mCdmaSubscriptionSource=" + mCdmaSubscriptionSource); 1645 pw.println(" mSubInfo=" + mSubInfo); 1646 pw.println(" mEriManager=" + mEriManager); 1647 pw.println(" mWakeLock=" + mWakeLock); 1648 pw.println(" mIsPhoneInEcmState=" + mIsPhoneInEcmState); 1649 if (VDBG) pw.println(" mImei=" + mImei); 1650 if (VDBG) pw.println(" mImeiSv=" + mImeiSv); 1651 if (VDBG) pw.println(" mEsn=" + mEsn); 1652 if (VDBG) pw.println(" mMeid=" + mMeid); 1653 pw.println(" mCarrierOtaSpNumSchema=" + mCarrierOtaSpNumSchema); 1654 pw.println(" getCdmaEriIconIndex()=" + getCdmaEriIconIndex()); 1655 pw.println(" getCdmaEriIconMode()=" + getCdmaEriIconMode()); 1656 pw.println(" getCdmaEriText()=" + getCdmaEriText()); 1657 pw.println(" isMinInfoReady()=" + isMinInfoReady()); 1658 pw.println(" isCspPlmnEnabled()=" + isCspPlmnEnabled()); 1659 } 1660} 1661