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