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