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