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