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