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