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