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