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