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