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