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