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