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