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