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.gsm; 18 19import android.content.ContentValues; 20import android.content.Context; 21import android.content.SharedPreferences; 22import android.database.SQLException; 23import android.net.Uri; 24import android.os.AsyncResult; 25import android.os.Handler; 26import android.os.Message; 27import android.os.Registrant; 28import android.os.RegistrantList; 29import android.os.SystemProperties; 30import android.preference.PreferenceManager; 31import android.provider.Telephony; 32import android.telecom.VideoProfile; 33import android.telephony.CellLocation; 34import android.telephony.PhoneNumberUtils; 35import android.telephony.ServiceState; 36import android.telephony.SubscriptionManager; 37import android.telephony.TelephonyManager; 38 39import com.android.ims.ImsManager; 40import com.android.internal.telephony.CallTracker; 41 42import android.text.TextUtils; 43import android.telephony.Rlog; 44import android.util.Log; 45 46import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE; 47import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; 48import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE; 49import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION; 50import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; 51import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; 52import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; 53import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; 54import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; 55import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; 56import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; 57 58import com.android.internal.telephony.dataconnection.DcTracker; 59import com.android.internal.telephony.Call; 60import com.android.internal.telephony.CallForwardInfo; 61import com.android.internal.telephony.CallStateException; 62import com.android.internal.telephony.CommandsInterface; 63import com.android.internal.telephony.Connection; 64import com.android.internal.telephony.IccPhoneBookInterfaceManager; 65import com.android.internal.telephony.MmiCode; 66import com.android.internal.telephony.OperatorInfo; 67import com.android.internal.telephony.Phone; 68import com.android.internal.telephony.PhoneBase; 69import com.android.internal.telephony.PhoneConstants; 70import com.android.internal.telephony.PhoneNotifier; 71import com.android.internal.telephony.PhoneProxy; 72import com.android.internal.telephony.PhoneSubInfo; 73import com.android.internal.telephony.TelephonyProperties; 74import com.android.internal.telephony.UUSInfo; 75import com.android.internal.telephony.imsphone.ImsPhone; 76import com.android.internal.telephony.test.SimulatedRadioControl; 77import com.android.internal.telephony.uicc.IccRecords; 78import com.android.internal.telephony.uicc.IccVmNotSupportedException; 79import com.android.internal.telephony.uicc.UiccCard; 80import com.android.internal.telephony.uicc.UiccCardApplication; 81import com.android.internal.telephony.uicc.UiccController; 82import com.android.internal.telephony.ServiceStateTracker; 83import com.android.internal.telephony.uicc.IsimRecords; 84import com.android.internal.telephony.uicc.IsimUiccRecords; 85 86import java.io.FileDescriptor; 87import java.io.PrintWriter; 88import java.util.ArrayList; 89import java.util.List; 90 91 92/** 93 * {@hide} 94 */ 95public class GSMPhone extends PhoneBase { 96 // NOTE that LOG_TAG here is "GSM", which means that log messages 97 // from this file will go into the radio log rather than the main 98 // log. (Use "adb logcat -b radio" to see them.) 99 static final String LOG_TAG = "GSMPhone"; 100 private static final boolean LOCAL_DEBUG = true; 101 private static final boolean VDBG = false; /* STOPSHIP if true */ 102 103 // Key used to read/write current ciphering state 104 public static final String CIPHERING_KEY = "ciphering_key"; 105 // Key used to read/write voice mail number 106 public static final String VM_NUMBER = "vm_number_key"; 107 // Key used to read/write the SIM IMSI used for storing the voice mail 108 public static final String VM_SIM_IMSI = "vm_sim_imsi_key"; 109 110 // Instance Variables 111 GsmCallTracker mCT; 112 GsmServiceStateTracker mSST; 113 ArrayList <GsmMmiCode> mPendingMMIs = new ArrayList<GsmMmiCode>(); 114 SimPhoneBookInterfaceManager mSimPhoneBookIntManager; 115 PhoneSubInfo mSubInfo; 116 117 118 Registrant mPostDialHandler; 119 120 /** List of Registrants to receive Supplementary Service Notifications. */ 121 RegistrantList mSsnRegistrants = new RegistrantList(); 122 123 // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started 124 private final RegistrantList mEcmTimerResetRegistrants = new RegistrantList(); 125 126 private String mImei; 127 private String mImeiSv; 128 private String mVmNumber; 129 130 private IsimUiccRecords mIsimUiccRecords; 131 132 // Create Cfu (Call forward unconditional) so that dialing number & 133 // mOnComplete (Message object passed by client) can be packed & 134 // given as a single Cfu object as user data to RIL. 135 private static class Cfu { 136 final String mSetCfNumber; 137 final Message mOnComplete; 138 139 Cfu(String cfNumber, Message onComplete) { 140 mSetCfNumber = cfNumber; 141 mOnComplete = onComplete; 142 } 143 } 144 145 // Constructors 146 147 public 148 GSMPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) { 149 super("GSM", notifier, context, ci, unitTestMode); 150 151 if (ci instanceof SimulatedRadioControl) { 152 mSimulatedRadioControl = (SimulatedRadioControl) ci; 153 } 154 155 mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM); 156 mCT = new GsmCallTracker(this); 157 158 mSST = new GsmServiceStateTracker(this); 159 mDcTracker = new DcTracker(this); 160 161 if (!unitTestMode) { 162 mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this); 163 mSubInfo = new PhoneSubInfo(this); 164 } 165 166 mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); 167 mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); 168 mCi.registerForOn(this, EVENT_RADIO_ON, null); 169 mCi.setOnUSSD(this, EVENT_USSD, null); 170 mCi.setOnSuppServiceNotification(this, EVENT_SSN, null); 171 mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); 172 mCi.setOnSs(this, EVENT_SS, null); 173 setProperties(); 174 } 175 176 public 177 GSMPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId) { 178 this(context, ci, notifier, false, phoneId); 179 } 180 181 public 182 GSMPhone(Context context, CommandsInterface ci, 183 PhoneNotifier notifier, boolean unitTestMode, int phoneId) { 184 super("GSM", notifier, context, ci, unitTestMode, phoneId); 185 186 if (ci instanceof SimulatedRadioControl) { 187 mSimulatedRadioControl = (SimulatedRadioControl) ci; 188 } 189 190 mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM); 191 mCT = new GsmCallTracker(this); 192 193 mSST = new GsmServiceStateTracker(this); 194 mDcTracker = new DcTracker(this); 195 196 if (!unitTestMode) { 197 mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this); 198 mSubInfo = new PhoneSubInfo(this); 199 } 200 201 mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); 202 mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); 203 mCi.registerForOn(this, EVENT_RADIO_ON, null); 204 mCi.setOnUSSD(this, EVENT_USSD, null); 205 mCi.setOnSuppServiceNotification(this, EVENT_SSN, null); 206 mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); 207 mCi.setOnSs(this, EVENT_SS, null); 208 setProperties(); 209 210 log("GSMPhone: constructor: sub = " + mPhoneId); 211 212 setProperties(); 213 } 214 215 protected void setProperties() { 216 TelephonyManager.from(mContext).setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_GSM); 217 } 218 219 @Override 220 public void dispose() { 221 synchronized(PhoneProxy.lockForRadioTechnologyChange) { 222 super.dispose(); 223 224 //Unregister from all former registered events 225 mCi.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE 226 unregisterForSimRecordEvents(); 227 mCi.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE 228 mCi.unregisterForOn(this); //EVENT_RADIO_ON 229 mSST.unregisterForNetworkAttached(this); //EVENT_REGISTERED_TO_NETWORK 230 mCi.unSetOnUSSD(this); 231 mCi.unSetOnSuppServiceNotification(this); 232 mCi.unSetOnSs(this); 233 234 mPendingMMIs.clear(); 235 236 //Force all referenced classes to unregister their former registered events 237 mCT.dispose(); 238 mDcTracker.dispose(); 239 mSST.dispose(); 240 mSimPhoneBookIntManager.dispose(); 241 mSubInfo.dispose(); 242 } 243 } 244 245 @Override 246 public void removeReferences() { 247 Rlog.d(LOG_TAG, "removeReferences"); 248 mSimulatedRadioControl = null; 249 mSimPhoneBookIntManager = null; 250 mSubInfo = null; 251 mCT = null; 252 mSST = null; 253 254 super.removeReferences(); 255 } 256 257 @Override 258 protected void finalize() { 259 if(LOCAL_DEBUG) Rlog.d(LOG_TAG, "GSMPhone finalized"); 260 } 261 262 @Override 263 public ServiceState 264 getServiceState() { 265 if (mSST == null || mSST.mSS.getState() != ServiceState.STATE_IN_SERVICE) { 266 if (mImsPhone != null) { 267 return ServiceState.mergeServiceStates( 268 (mSST == null) ? new ServiceState() : mSST.mSS, 269 mImsPhone.getServiceState()); 270 } 271 } 272 273 if (mSST != null) { 274 return mSST.mSS; 275 } else { 276 // avoid potential NPE in EmergencyCallHelper during Phone switch 277 return new ServiceState(); 278 } 279 } 280 281 @Override 282 public CellLocation getCellLocation() { 283 return mSST.getCellLocation(); 284 } 285 286 @Override 287 public PhoneConstants.State getState() { 288 if (mImsPhone != null) { 289 PhoneConstants.State imsState = mImsPhone.getState(); 290 if (imsState != PhoneConstants.State.IDLE) { 291 return imsState; 292 } 293 } 294 295 return mCT.mState; 296 } 297 298 @Override 299 public int getPhoneType() { 300 return PhoneConstants.PHONE_TYPE_GSM; 301 } 302 303 @Override 304 public ServiceStateTracker getServiceStateTracker() { 305 return mSST; 306 } 307 308 @Override 309 public CallTracker getCallTracker() { 310 return mCT; 311 } 312 313 // pending voice mail count updated after phone creation 314 private void updateVoiceMail() { 315 int countVoiceMessages = 0; 316 IccRecords r = mIccRecords.get(); 317 if (r != null) { 318 // get voice mail count from SIM 319 countVoiceMessages = r.getVoiceMessageCount(); 320 } 321 int countVoiceMessagesStored = getStoredVoiceMessageCount(); 322 if (countVoiceMessages == -1 && countVoiceMessagesStored != 0) { 323 countVoiceMessages = countVoiceMessagesStored; 324 } 325 Rlog.d(LOG_TAG, "updateVoiceMail countVoiceMessages = " + countVoiceMessages 326 +" subId "+getSubId()); 327 setVoiceMessageCount(countVoiceMessages); 328 } 329 330 @Override 331 public List<? extends MmiCode> 332 getPendingMmiCodes() { 333 return mPendingMMIs; 334 } 335 336 @Override 337 public PhoneConstants.DataState getDataConnectionState(String apnType) { 338 PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED; 339 340 if (mSST == null) { 341 // Radio Technology Change is ongoning, dispose() and removeReferences() have 342 // already been called 343 344 ret = PhoneConstants.DataState.DISCONNECTED; 345 } else if (!apnType.equals(PhoneConstants.APN_TYPE_EMERGENCY) && 346 mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) { 347 // If we're out of service, open TCP sockets may still work 348 // but no data will flow 349 350 // Emergency APN is available even in Out Of Service 351 // Pass the actual State of EPDN 352 353 ret = PhoneConstants.DataState.DISCONNECTED; 354 } else if (mDcTracker.isApnTypeEnabled(apnType) == false || 355 mDcTracker.isApnTypeActive(apnType) == false) { 356 //TODO: isApnTypeActive() is just checking whether ApnContext holds 357 // Dataconnection or not. Checking each ApnState below should 358 // provide the same state. Calling isApnTypeActive() can be removed. 359 ret = PhoneConstants.DataState.DISCONNECTED; 360 } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */ 361 switch (mDcTracker.getState(apnType)) { 362 case RETRYING: 363 case FAILED: 364 case IDLE: 365 ret = PhoneConstants.DataState.DISCONNECTED; 366 break; 367 368 case CONNECTED: 369 case DISCONNECTING: 370 if ( mCT.mState != PhoneConstants.State.IDLE 371 && !mSST.isConcurrentVoiceAndDataAllowed()) { 372 ret = PhoneConstants.DataState.SUSPENDED; 373 } else { 374 ret = PhoneConstants.DataState.CONNECTED; 375 } 376 break; 377 378 case CONNECTING: 379 case SCANNING: 380 ret = PhoneConstants.DataState.CONNECTING; 381 break; 382 } 383 } 384 385 return ret; 386 } 387 388 @Override 389 public DataActivityState getDataActivityState() { 390 DataActivityState ret = DataActivityState.NONE; 391 392 if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) { 393 switch (mDcTracker.getActivity()) { 394 case DATAIN: 395 ret = DataActivityState.DATAIN; 396 break; 397 398 case DATAOUT: 399 ret = DataActivityState.DATAOUT; 400 break; 401 402 case DATAINANDOUT: 403 ret = DataActivityState.DATAINANDOUT; 404 break; 405 406 case DORMANT: 407 ret = DataActivityState.DORMANT; 408 break; 409 410 default: 411 ret = DataActivityState.NONE; 412 break; 413 } 414 } 415 416 return ret; 417 } 418 419 /** 420 * Notify any interested party of a Phone state change 421 * {@link com.android.internal.telephony.PhoneConstants.State} 422 */ 423 /*package*/ void notifyPhoneStateChanged() { 424 mNotifier.notifyPhoneState(this); 425 } 426 427 /** 428 * Notify registrants of a change in the call state. This notifies changes in 429 * {@link com.android.internal.telephony.Call.State}. Use this when changes 430 * in the precise call state are needed, else use notifyPhoneStateChanged. 431 */ 432 /*package*/ void notifyPreciseCallStateChanged() { 433 /* we'd love it if this was package-scoped*/ 434 super.notifyPreciseCallStateChangedP(); 435 } 436 437 public void notifyNewRingingConnection(Connection c) { 438 super.notifyNewRingingConnectionP(c); 439 } 440 441 /*package*/ void 442 notifyDisconnect(Connection cn) { 443 mDisconnectRegistrants.notifyResult(cn); 444 445 mNotifier.notifyDisconnectCause(cn.getDisconnectCause(), cn.getPreciseDisconnectCause()); 446 } 447 448 void notifyUnknownConnection(Connection cn) { 449 mUnknownConnectionRegistrants.notifyResult(cn); 450 } 451 452 void notifySuppServiceFailed(SuppService code) { 453 mSuppServiceFailedRegistrants.notifyResult(code); 454 } 455 456 /*package*/ void 457 notifyServiceStateChanged(ServiceState ss) { 458 super.notifyServiceStateChangedP(ss); 459 } 460 461 /*package*/ 462 void notifyLocationChanged() { 463 mNotifier.notifyCellLocation(this); 464 } 465 466 @Override 467 public void 468 notifyCallForwardingIndicator() { 469 mNotifier.notifyCallForwardingChanged(this); 470 } 471 472 // override for allowing access from other classes of this package 473 /** 474 * {@inheritDoc} 475 */ 476 @Override 477 public void 478 setSystemProperty(String property, String value) { 479 TelephonyManager.setTelephonyProperty(mPhoneId, property, value); 480 } 481 482 @Override 483 public void registerForSuppServiceNotification( 484 Handler h, int what, Object obj) { 485 mSsnRegistrants.addUnique(h, what, obj); 486 if (mSsnRegistrants.size() == 1) mCi.setSuppServiceNotifications(true, null); 487 } 488 489 @Override 490 public void unregisterForSuppServiceNotification(Handler h) { 491 mSsnRegistrants.remove(h); 492 if (mSsnRegistrants.size() == 0) mCi.setSuppServiceNotifications(false, null); 493 } 494 495 @Override 496 public void registerForSimRecordsLoaded(Handler h, int what, Object obj) { 497 mSimRecordsLoadedRegistrants.addUnique(h, what, obj); 498 } 499 500 @Override 501 public void unregisterForSimRecordsLoaded(Handler h) { 502 mSimRecordsLoadedRegistrants.remove(h); 503 } 504 505 @Override 506 public void 507 acceptCall(int videoState) throws CallStateException { 508 ImsPhone imsPhone = mImsPhone; 509 if ( imsPhone != null && imsPhone.getRingingCall().isRinging() ) { 510 imsPhone.acceptCall(videoState); 511 } else { 512 mCT.acceptCall(); 513 } 514 } 515 516 @Override 517 public void 518 rejectCall() throws CallStateException { 519 mCT.rejectCall(); 520 } 521 522 @Override 523 public void 524 switchHoldingAndActive() throws CallStateException { 525 mCT.switchWaitingOrHoldingAndActive(); 526 } 527 528 @Override 529 public boolean canConference() { 530 boolean canImsConference = false; 531 if (mImsPhone != null) { 532 canImsConference = mImsPhone.canConference(); 533 } 534 return mCT.canConference() || canImsConference; 535 } 536 537 public boolean canDial() { 538 return mCT.canDial(); 539 } 540 541 @Override 542 public void conference() { 543 if (mImsPhone != null && mImsPhone.canConference()) { 544 log("conference() - delegated to IMS phone"); 545 mImsPhone.conference(); 546 return; 547 } 548 mCT.conference(); 549 } 550 551 @Override 552 public void clearDisconnected() { 553 mCT.clearDisconnected(); 554 } 555 556 @Override 557 public boolean canTransfer() { 558 return mCT.canTransfer(); 559 } 560 561 @Override 562 public void explicitCallTransfer() { 563 mCT.explicitCallTransfer(); 564 } 565 566 @Override 567 public GsmCall 568 getForegroundCall() { 569 return mCT.mForegroundCall; 570 } 571 572 @Override 573 public GsmCall 574 getBackgroundCall() { 575 return mCT.mBackgroundCall; 576 } 577 578 @Override 579 public Call getRingingCall() { 580 ImsPhone imsPhone = mImsPhone; 581 if ( mCT.mRingingCall != null && mCT.mRingingCall.isRinging() ) { 582 return mCT.mRingingCall; 583 } else if ( imsPhone != null ) { 584 return imsPhone.getRingingCall(); 585 } 586 return mCT.mRingingCall; 587 } 588 589 private boolean handleCallDeflectionIncallSupplementaryService( 590 String dialString) { 591 if (dialString.length() > 1) { 592 return false; 593 } 594 595 if (getRingingCall().getState() != GsmCall.State.IDLE) { 596 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "MmiCode 0: rejectCall"); 597 try { 598 mCT.rejectCall(); 599 } catch (CallStateException e) { 600 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, 601 "reject failed", e); 602 notifySuppServiceFailed(Phone.SuppService.REJECT); 603 } 604 } else if (getBackgroundCall().getState() != GsmCall.State.IDLE) { 605 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, 606 "MmiCode 0: hangupWaitingOrBackground"); 607 mCT.hangupWaitingOrBackground(); 608 } 609 610 return true; 611 } 612 613 private boolean handleCallWaitingIncallSupplementaryService( 614 String dialString) { 615 int len = dialString.length(); 616 617 if (len > 2) { 618 return false; 619 } 620 621 GsmCall call = getForegroundCall(); 622 623 try { 624 if (len > 1) { 625 char ch = dialString.charAt(1); 626 int callIndex = ch - '0'; 627 628 if (callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) { 629 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, 630 "MmiCode 1: hangupConnectionByIndex " + 631 callIndex); 632 mCT.hangupConnectionByIndex(call, callIndex); 633 } 634 } else { 635 if (call.getState() != GsmCall.State.IDLE) { 636 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, 637 "MmiCode 1: hangup foreground"); 638 //mCT.hangupForegroundResumeBackground(); 639 mCT.hangup(call); 640 } else { 641 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, 642 "MmiCode 1: switchWaitingOrHoldingAndActive"); 643 mCT.switchWaitingOrHoldingAndActive(); 644 } 645 } 646 } catch (CallStateException e) { 647 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, 648 "hangup failed", e); 649 notifySuppServiceFailed(Phone.SuppService.HANGUP); 650 } 651 652 return true; 653 } 654 655 private boolean handleCallHoldIncallSupplementaryService(String dialString) { 656 int len = dialString.length(); 657 658 if (len > 2) { 659 return false; 660 } 661 662 GsmCall call = getForegroundCall(); 663 664 if (len > 1) { 665 try { 666 char ch = dialString.charAt(1); 667 int callIndex = ch - '0'; 668 GsmConnection conn = mCT.getConnectionByIndex(call, callIndex); 669 670 // gsm index starts at 1, up to 5 connections in a call, 671 if (conn != null && callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) { 672 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "MmiCode 2: separate call "+ 673 callIndex); 674 mCT.separate(conn); 675 } else { 676 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "separate: invalid call index "+ 677 callIndex); 678 notifySuppServiceFailed(Phone.SuppService.SEPARATE); 679 } 680 } catch (CallStateException e) { 681 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, 682 "separate failed", e); 683 notifySuppServiceFailed(Phone.SuppService.SEPARATE); 684 } 685 } else { 686 try { 687 if (getRingingCall().getState() != GsmCall.State.IDLE) { 688 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, 689 "MmiCode 2: accept ringing call"); 690 mCT.acceptCall(); 691 } else { 692 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, 693 "MmiCode 2: switchWaitingOrHoldingAndActive"); 694 mCT.switchWaitingOrHoldingAndActive(); 695 } 696 } catch (CallStateException e) { 697 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, 698 "switch failed", e); 699 notifySuppServiceFailed(Phone.SuppService.SWITCH); 700 } 701 } 702 703 return true; 704 } 705 706 private boolean handleMultipartyIncallSupplementaryService( 707 String dialString) { 708 if (dialString.length() > 1) { 709 return false; 710 } 711 712 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "MmiCode 3: merge calls"); 713 conference(); 714 return true; 715 } 716 717 private boolean handleEctIncallSupplementaryService(String dialString) { 718 719 int len = dialString.length(); 720 721 if (len != 1) { 722 return false; 723 } 724 725 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "MmiCode 4: explicit call transfer"); 726 explicitCallTransfer(); 727 return true; 728 } 729 730 private boolean handleCcbsIncallSupplementaryService(String dialString) { 731 if (dialString.length() > 1) { 732 return false; 733 } 734 735 Rlog.i(LOG_TAG, "MmiCode 5: CCBS not supported!"); 736 // Treat it as an "unknown" service. 737 notifySuppServiceFailed(Phone.SuppService.UNKNOWN); 738 return true; 739 } 740 741 @Override 742 public boolean handleInCallMmiCommands(String dialString) throws CallStateException { 743 ImsPhone imsPhone = mImsPhone; 744 if (imsPhone != null 745 && imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) { 746 return imsPhone.handleInCallMmiCommands(dialString); 747 } 748 749 if (!isInCall()) { 750 return false; 751 } 752 753 if (TextUtils.isEmpty(dialString)) { 754 return false; 755 } 756 757 boolean result = false; 758 char ch = dialString.charAt(0); 759 switch (ch) { 760 case '0': 761 result = handleCallDeflectionIncallSupplementaryService( 762 dialString); 763 break; 764 case '1': 765 result = handleCallWaitingIncallSupplementaryService( 766 dialString); 767 break; 768 case '2': 769 result = handleCallHoldIncallSupplementaryService(dialString); 770 break; 771 case '3': 772 result = handleMultipartyIncallSupplementaryService(dialString); 773 break; 774 case '4': 775 result = handleEctIncallSupplementaryService(dialString); 776 break; 777 case '5': 778 result = handleCcbsIncallSupplementaryService(dialString); 779 break; 780 default: 781 break; 782 } 783 784 return result; 785 } 786 787 boolean isInCall() { 788 GsmCall.State foregroundCallState = getForegroundCall().getState(); 789 GsmCall.State backgroundCallState = getBackgroundCall().getState(); 790 GsmCall.State ringingCallState = getRingingCall().getState(); 791 792 return (foregroundCallState.isAlive() || 793 backgroundCallState.isAlive() || 794 ringingCallState.isAlive()); 795 } 796 797 @Override 798 public Connection 799 dial(String dialString, int videoState) throws CallStateException { 800 return dial(dialString, null, videoState); 801 } 802 803 @Override 804 public Connection 805 dial (String dialString, UUSInfo uusInfo, int videoState) throws CallStateException { 806 ImsPhone imsPhone = mImsPhone; 807 808 boolean imsUseEnabled = 809 ImsManager.isVolteEnabledByPlatform(mContext) && 810 ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mContext) && 811 ImsManager.isNonTtyOrTtyOnVolteEnabled(mContext); 812 if (!imsUseEnabled) { 813 Rlog.w(LOG_TAG, "IMS is disabled: forced to CS"); 814 } 815 816 if (LOCAL_DEBUG) { 817 Rlog.d(LOG_TAG, "imsUseEnabled=" + imsUseEnabled + ", imsPhone=" + imsPhone 818 + ", imsPhone.isVolteEnabled()=" 819 + ((imsPhone != null) ? imsPhone.isVolteEnabled() : "N/A") 820 + ", imsPhone.getServiceState().getState()=" 821 + ((imsPhone != null) ? imsPhone.getServiceState().getState() : "N/A")); 822 } 823 824 if (imsUseEnabled && imsPhone != null && imsPhone.isVolteEnabled() 825 && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE 826 && !PhoneNumberUtils.isEmergencyNumber(dialString)) 827 || (PhoneNumberUtils.isEmergencyNumber(dialString) 828 && mContext.getResources().getBoolean( 829 com.android.internal.R.bool.useImsAlwaysForEmergencyCall))) ) { 830 try { 831 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "Trying IMS PS call"); 832 return imsPhone.dial(dialString, videoState); 833 } catch (CallStateException e) { 834 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "IMS PS call exception " + e + 835 "imsUseEnabled =" + imsUseEnabled + ", imsPhone =" + imsPhone); 836 if (!ImsPhone.CS_FALLBACK.equals(e.getMessage())) { 837 CallStateException ce = new CallStateException(e.getMessage()); 838 ce.setStackTrace(e.getStackTrace()); 839 throw ce; 840 } 841 } 842 } 843 844 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "Trying (non-IMS) CS call"); 845 return dialInternal(dialString, null, VideoProfile.VideoState.AUDIO_ONLY); 846 } 847 848 @Override 849 protected Connection 850 dialInternal (String dialString, UUSInfo uusInfo, int videoState) 851 throws CallStateException { 852 853 // Need to make sure dialString gets parsed properly 854 String newDialString = PhoneNumberUtils.stripSeparators(dialString); 855 856 // handle in-call MMI first if applicable 857 if (handleInCallMmiCommands(newDialString)) { 858 return null; 859 } 860 861 // Only look at the Network portion for mmi 862 String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString); 863 GsmMmiCode mmi = 864 GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get()); 865 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, 866 "dialing w/ mmi '" + mmi + "'..."); 867 868 if (mmi == null) { 869 return mCT.dial(newDialString, uusInfo); 870 } else if (mmi.isTemporaryModeCLIR()) { 871 return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo); 872 } else { 873 mPendingMMIs.add(mmi); 874 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 875 mmi.processCode(); 876 877 // FIXME should this return null or something else? 878 return null; 879 } 880 } 881 882 @Override 883 public boolean handlePinMmi(String dialString) { 884 GsmMmiCode mmi = GsmMmiCode.newFromDialString(dialString, this, mUiccApplication.get()); 885 886 if (mmi != null && mmi.isPinPukCommand()) { 887 mPendingMMIs.add(mmi); 888 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 889 mmi.processCode(); 890 return true; 891 } 892 893 return false; 894 } 895 896 @Override 897 public void sendUssdResponse(String ussdMessge) { 898 GsmMmiCode mmi = GsmMmiCode.newFromUssdUserInput(ussdMessge, this, mUiccApplication.get()); 899 mPendingMMIs.add(mmi); 900 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 901 mmi.sendUssd(ussdMessge); 902 } 903 904 @Override 905 public void 906 sendDtmf(char c) { 907 if (!PhoneNumberUtils.is12Key(c)) { 908 Rlog.e(LOG_TAG, 909 "sendDtmf called with invalid character '" + c + "'"); 910 } else { 911 if (mCT.mState == PhoneConstants.State.OFFHOOK) { 912 mCi.sendDtmf(c, null); 913 } 914 } 915 } 916 917 @Override 918 public void 919 startDtmf(char c) { 920 if (!PhoneNumberUtils.is12Key(c)) { 921 Rlog.e(LOG_TAG, 922 "startDtmf called with invalid character '" + c + "'"); 923 } else { 924 mCi.startDtmf(c, null); 925 } 926 } 927 928 @Override 929 public void 930 stopDtmf() { 931 mCi.stopDtmf(null); 932 } 933 934 public void 935 sendBurstDtmf(String dtmfString) { 936 Rlog.e(LOG_TAG, "[GSMPhone] sendBurstDtmf() is a CDMA method"); 937 } 938 939 @Override 940 public void 941 setRadioPower(boolean power) { 942 mSST.setRadioPower(power); 943 } 944 945 private void storeVoiceMailNumber(String number) { 946 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); 947 SharedPreferences.Editor editor = sp.edit(); 948 editor.putString(VM_NUMBER + getPhoneId(), number); 949 editor.apply(); 950 setVmSimImsi(getSubscriberId()); 951 } 952 953 @Override 954 public String getVoiceMailNumber() { 955 // Read from the SIM. If its null, try reading from the shared preference area. 956 IccRecords r = mIccRecords.get(); 957 String number = (r != null) ? r.getVoiceMailNumber() : ""; 958 if (TextUtils.isEmpty(number)) { 959 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); 960 number = sp.getString(VM_NUMBER + getPhoneId(), null); 961 } 962 963 if (TextUtils.isEmpty(number)) { 964 String[] listArray = getContext().getResources() 965 .getStringArray(com.android.internal.R.array.config_default_vm_number); 966 if (listArray != null && listArray.length > 0) { 967 for (int i=0; i<listArray.length; i++) { 968 if (!TextUtils.isEmpty(listArray[i])) { 969 String[] defaultVMNumberArray = listArray[i].split(";"); 970 if (defaultVMNumberArray != null && defaultVMNumberArray.length > 0) { 971 if (defaultVMNumberArray.length == 1) { 972 number = defaultVMNumberArray[0]; 973 } else if (defaultVMNumberArray.length == 2 && 974 !TextUtils.isEmpty(defaultVMNumberArray[1]) && 975 defaultVMNumberArray[1].equalsIgnoreCase(getGroupIdLevel1())) { 976 number = defaultVMNumberArray[0]; 977 break; 978 } 979 } 980 } 981 } 982 } 983 } 984 return number; 985 } 986 987 private String getVmSimImsi() { 988 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); 989 return sp.getString(VM_SIM_IMSI + getPhoneId(), null); 990 } 991 992 private void setVmSimImsi(String imsi) { 993 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); 994 SharedPreferences.Editor editor = sp.edit(); 995 editor.putString(VM_SIM_IMSI + getPhoneId(), imsi); 996 editor.apply(); 997 } 998 999 @Override 1000 public String getVoiceMailAlphaTag() { 1001 String ret; 1002 IccRecords r = mIccRecords.get(); 1003 1004 ret = (r != null) ? r.getVoiceMailAlphaTag() : ""; 1005 1006 if (ret == null || ret.length() == 0) { 1007 return mContext.getText( 1008 com.android.internal.R.string.defaultVoiceMailAlphaTag).toString(); 1009 } 1010 1011 return ret; 1012 } 1013 1014 @Override 1015 public String getDeviceId() { 1016 return mImei; 1017 } 1018 1019 @Override 1020 public String getDeviceSvn() { 1021 return mImeiSv; 1022 } 1023 1024 @Override 1025 public IsimRecords getIsimRecords() { 1026 return mIsimUiccRecords; 1027 } 1028 1029 @Override 1030 public String getImei() { 1031 return mImei; 1032 } 1033 1034 @Override 1035 public String getEsn() { 1036 Rlog.e(LOG_TAG, "[GSMPhone] getEsn() is a CDMA method"); 1037 return "0"; 1038 } 1039 1040 @Override 1041 public String getMeid() { 1042 Rlog.e(LOG_TAG, "[GSMPhone] getMeid() is a CDMA method"); 1043 return "0"; 1044 } 1045 1046 @Override 1047 public String getNai() { 1048 IccRecords r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP2); 1049 if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) { 1050 Rlog.v(LOG_TAG, "IccRecords is " + r); 1051 } 1052 return (r != null) ? r.getNAI() : null; 1053 } 1054 1055 @Override 1056 public String getSubscriberId() { 1057 IccRecords r = mIccRecords.get(); 1058 return (r != null) ? r.getIMSI() : null; 1059 } 1060 1061 @Override 1062 public String getGroupIdLevel1() { 1063 IccRecords r = mIccRecords.get(); 1064 return (r != null) ? r.getGid1() : null; 1065 } 1066 1067 @Override 1068 public String getLine1Number() { 1069 IccRecords r = mIccRecords.get(); 1070 return (r != null) ? r.getMsisdnNumber() : null; 1071 } 1072 1073 @Override 1074 public String getMsisdn() { 1075 IccRecords r = mIccRecords.get(); 1076 return (r != null) ? r.getMsisdnNumber() : null; 1077 } 1078 1079 @Override 1080 public String getLine1AlphaTag() { 1081 IccRecords r = mIccRecords.get(); 1082 return (r != null) ? r.getMsisdnAlphaTag() : null; 1083 } 1084 1085 @Override 1086 public boolean setLine1Number(String alphaTag, String number, Message onComplete) { 1087 IccRecords r = mIccRecords.get(); 1088 if (r != null) { 1089 r.setMsisdnNumber(alphaTag, number, onComplete); 1090 return true; 1091 } else { 1092 return false; 1093 } 1094 } 1095 1096 @Override 1097 public void setVoiceMailNumber(String alphaTag, 1098 String voiceMailNumber, 1099 Message onComplete) { 1100 1101 Message resp; 1102 mVmNumber = voiceMailNumber; 1103 resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete); 1104 IccRecords r = mIccRecords.get(); 1105 if (r != null) { 1106 r.setVoiceMailNumber(alphaTag, mVmNumber, resp); 1107 } 1108 } 1109 1110 private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { 1111 switch (commandInterfaceCFReason) { 1112 case CF_REASON_UNCONDITIONAL: 1113 case CF_REASON_BUSY: 1114 case CF_REASON_NO_REPLY: 1115 case CF_REASON_NOT_REACHABLE: 1116 case CF_REASON_ALL: 1117 case CF_REASON_ALL_CONDITIONAL: 1118 return true; 1119 default: 1120 return false; 1121 } 1122 } 1123 1124 @Override 1125 public String getSystemProperty(String property, String defValue) { 1126 if(getUnitTestMode()) { 1127 return null; 1128 } 1129 return TelephonyManager.getTelephonyProperty(mPhoneId, property, defValue); 1130 } 1131 1132 private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) { 1133 switch (commandInterfaceCFAction) { 1134 case CF_ACTION_DISABLE: 1135 case CF_ACTION_ENABLE: 1136 case CF_ACTION_REGISTRATION: 1137 case CF_ACTION_ERASURE: 1138 return true; 1139 default: 1140 return false; 1141 } 1142 } 1143 1144 public void updateDataConnectionTracker() { 1145 ((DcTracker)mDcTracker).update(); 1146 } 1147 1148 protected boolean isCfEnable(int action) { 1149 return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION); 1150 } 1151 1152 @Override 1153 public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { 1154 ImsPhone imsPhone = mImsPhone; 1155 if ((imsPhone != null) 1156 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) { 1157 imsPhone.getCallForwardingOption(commandInterfaceCFReason, onComplete); 1158 return; 1159 } 1160 1161 if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { 1162 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "requesting call forwarding query."); 1163 Message resp; 1164 if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) { 1165 resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete); 1166 } else { 1167 resp = onComplete; 1168 } 1169 mCi.queryCallForwardStatus(commandInterfaceCFReason,0,null,resp); 1170 } 1171 } 1172 1173 @Override 1174 public void setCallForwardingOption(int commandInterfaceCFAction, 1175 int commandInterfaceCFReason, 1176 String dialingNumber, 1177 int timerSeconds, 1178 Message onComplete) { 1179 ImsPhone imsPhone = mImsPhone; 1180 if ((imsPhone != null) 1181 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) { 1182 imsPhone.setCallForwardingOption(commandInterfaceCFAction, 1183 commandInterfaceCFReason, dialingNumber, timerSeconds, onComplete); 1184 return; 1185 } 1186 1187 if ( (isValidCommandInterfaceCFAction(commandInterfaceCFAction)) && 1188 (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) { 1189 1190 Message resp; 1191 if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) { 1192 Cfu cfu = new Cfu(dialingNumber, onComplete); 1193 resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE, 1194 isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cfu); 1195 } else { 1196 resp = onComplete; 1197 } 1198 mCi.setCallForward(commandInterfaceCFAction, 1199 commandInterfaceCFReason, 1200 CommandsInterface.SERVICE_CLASS_VOICE, 1201 dialingNumber, 1202 timerSeconds, 1203 resp); 1204 } 1205 } 1206 1207 @Override 1208 public void getOutgoingCallerIdDisplay(Message onComplete) { 1209 mCi.getCLIR(onComplete); 1210 } 1211 1212 @Override 1213 public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, 1214 Message onComplete) { 1215 mCi.setCLIR(commandInterfaceCLIRMode, 1216 obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete)); 1217 } 1218 1219 @Override 1220 public void getCallWaiting(Message onComplete) { 1221 ImsPhone imsPhone = mImsPhone; 1222 if ((imsPhone != null) 1223 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) { 1224 imsPhone.getCallWaiting(onComplete); 1225 return; 1226 } 1227 1228 //As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service 1229 //class parameter in call waiting interrogation to network 1230 mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_NONE, onComplete); 1231 } 1232 1233 @Override 1234 public void setCallWaiting(boolean enable, Message onComplete) { 1235 ImsPhone imsPhone = mImsPhone; 1236 if ((imsPhone != null) 1237 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) { 1238 imsPhone.setCallWaiting(enable, onComplete); 1239 return; 1240 } 1241 1242 mCi.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete); 1243 } 1244 1245 @Override 1246 public void 1247 getAvailableNetworks(Message response) { 1248 mCi.getAvailableNetworks(response); 1249 } 1250 1251 @Override 1252 public void 1253 getNeighboringCids(Message response) { 1254 mCi.getNeighboringCids(response); 1255 } 1256 1257 @Override 1258 public void setOnPostDialCharacter(Handler h, int what, Object obj) { 1259 mPostDialHandler = new Registrant(h, what, obj); 1260 } 1261 1262 @Override 1263 public void setUiTTYMode(int uiTtyMode, Message onComplete) { 1264 if (mImsPhone != null) { 1265 mImsPhone.setUiTTYMode(uiTtyMode, onComplete); 1266 } 1267 } 1268 1269 @Override 1270 public void setMute(boolean muted) { 1271 mCT.setMute(muted); 1272 } 1273 1274 @Override 1275 public boolean getMute() { 1276 return mCT.getMute(); 1277 } 1278 1279 @Override 1280 public void getDataCallList(Message response) { 1281 mCi.getDataCallList(response); 1282 } 1283 1284 @Override 1285 public void updateServiceLocation() { 1286 mSST.enableSingleLocationUpdate(); 1287 } 1288 1289 @Override 1290 public void enableLocationUpdates() { 1291 mSST.enableLocationUpdates(); 1292 } 1293 1294 @Override 1295 public void disableLocationUpdates() { 1296 mSST.disableLocationUpdates(); 1297 } 1298 1299 @Override 1300 public boolean getDataRoamingEnabled() { 1301 return mDcTracker.getDataOnRoamingEnabled(); 1302 } 1303 1304 @Override 1305 public void setDataRoamingEnabled(boolean enable) { 1306 mDcTracker.setDataOnRoamingEnabled(enable); 1307 } 1308 1309 @Override 1310 public boolean getDataEnabled() { 1311 return mDcTracker.getDataEnabled(); 1312 } 1313 1314 @Override 1315 public void setDataEnabled(boolean enable) { 1316 mDcTracker.setDataEnabled(enable); 1317 } 1318 1319 /** 1320 * Removes the given MMI from the pending list and notifies 1321 * registrants that it is complete. 1322 * @param mmi MMI that is done 1323 */ 1324 /*package*/ void 1325 onMMIDone(GsmMmiCode mmi) { 1326 /* Only notify complete if it's on the pending list. 1327 * Otherwise, it's already been handled (eg, previously canceled). 1328 * The exception is cancellation of an incoming USSD-REQUEST, which is 1329 * not on the list. 1330 */ 1331 if (mPendingMMIs.remove(mmi) || mmi.isUssdRequest() || mmi.isSsInfo()) { 1332 mMmiCompleteRegistrants.notifyRegistrants( 1333 new AsyncResult(null, mmi, null)); 1334 } 1335 } 1336 1337 1338 private void 1339 onNetworkInitiatedUssd(GsmMmiCode mmi) { 1340 mMmiCompleteRegistrants.notifyRegistrants( 1341 new AsyncResult(null, mmi, null)); 1342 } 1343 1344 1345 /** ussdMode is one of CommandsInterface.USSD_MODE_* */ 1346 private void 1347 onIncomingUSSD (int ussdMode, String ussdMessage) { 1348 boolean isUssdError; 1349 boolean isUssdRequest; 1350 boolean isUssdRelease; 1351 1352 isUssdRequest 1353 = (ussdMode == CommandsInterface.USSD_MODE_REQUEST); 1354 1355 isUssdError 1356 = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY 1357 && ussdMode != CommandsInterface.USSD_MODE_REQUEST); 1358 1359 isUssdRelease = (ussdMode == CommandsInterface.USSD_MODE_NW_RELEASE); 1360 1361 // See comments in GsmMmiCode.java 1362 // USSD requests aren't finished until one 1363 // of these two events happen 1364 GsmMmiCode found = null; 1365 for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) { 1366 if(mPendingMMIs.get(i).isPendingUSSD()) { 1367 found = mPendingMMIs.get(i); 1368 break; 1369 } 1370 } 1371 1372 if (found != null) { 1373 // Complete pending USSD 1374 1375 if (isUssdRelease) { 1376 found.onUssdRelease(); 1377 } else if (isUssdError) { 1378 found.onUssdFinishedError(); 1379 } else { 1380 found.onUssdFinished(ussdMessage, isUssdRequest); 1381 } 1382 } else { // pending USSD not found 1383 // The network may initiate its own USSD request 1384 1385 // ignore everything that isnt a Notify or a Request 1386 // also, discard if there is no message to present 1387 if (!isUssdError && ussdMessage != null) { 1388 GsmMmiCode mmi; 1389 mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage, 1390 isUssdRequest, 1391 GSMPhone.this, 1392 mUiccApplication.get()); 1393 onNetworkInitiatedUssd(mmi); 1394 } 1395 } 1396 } 1397 1398 /** 1399 * Make sure the network knows our preferred setting. 1400 */ 1401 protected void syncClirSetting() { 1402 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); 1403 int clirSetting = sp.getInt(CLIR_KEY + getPhoneId(), -1); 1404 if (clirSetting >= 0) { 1405 mCi.setCLIR(clirSetting, null); 1406 } 1407 } 1408 1409 @Override 1410 public void handleMessage (Message msg) { 1411 AsyncResult ar; 1412 Message onComplete; 1413 1414 // messages to be handled whether or not the phone is being destroyed 1415 // should only include messages which are being re-directed and do not use 1416 // resources of the phone being destroyed 1417 switch (msg.what) { 1418 // handle the select network completion callbacks. 1419 case EVENT_SET_NETWORK_MANUAL_COMPLETE: 1420 case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE: 1421 super.handleMessage(msg); 1422 return; 1423 } 1424 1425 if (!mIsTheCurrentActivePhone) { 1426 Rlog.e(LOG_TAG, "Received message " + msg + 1427 "[" + msg.what + "] while being destroyed. Ignoring."); 1428 return; 1429 } 1430 switch (msg.what) { 1431 case EVENT_RADIO_AVAILABLE: { 1432 mCi.getBasebandVersion( 1433 obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE)); 1434 1435 mCi.getIMEI(obtainMessage(EVENT_GET_IMEI_DONE)); 1436 mCi.getIMEISV(obtainMessage(EVENT_GET_IMEISV_DONE)); 1437 mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY)); 1438 } 1439 break; 1440 1441 case EVENT_RADIO_ON: 1442 // do-nothing 1443 break; 1444 1445 case EVENT_REGISTERED_TO_NETWORK: 1446 syncClirSetting(); 1447 break; 1448 1449 case EVENT_SIM_RECORDS_LOADED: 1450 updateCurrentCarrierInProvider(); 1451 1452 // Check if this is a different SIM than the previous one. If so unset the 1453 // voice mail number. 1454 String imsi = getVmSimImsi(); 1455 String imsiFromSIM = getSubscriberId(); 1456 if (imsi != null && imsiFromSIM != null && !imsiFromSIM.equals(imsi)) { 1457 storeVoiceMailNumber(null); 1458 setVmSimImsi(null); 1459 } 1460 1461 mSimRecordsLoadedRegistrants.notifyRegistrants(); 1462 updateVoiceMail(); 1463 break; 1464 1465 case EVENT_GET_BASEBAND_VERSION_DONE: 1466 ar = (AsyncResult)msg.obj; 1467 1468 if (ar.exception != null) { 1469 break; 1470 } 1471 1472 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "Baseband version: " + ar.result); 1473 TelephonyManager.from(mContext).setBasebandVersionForPhone(getPhoneId(), 1474 (String)ar.result); 1475 break; 1476 1477 case EVENT_GET_IMEI_DONE: 1478 ar = (AsyncResult)msg.obj; 1479 1480 if (ar.exception != null) { 1481 break; 1482 } 1483 1484 mImei = (String)ar.result; 1485 break; 1486 1487 case EVENT_GET_IMEISV_DONE: 1488 ar = (AsyncResult)msg.obj; 1489 1490 if (ar.exception != null) { 1491 break; 1492 } 1493 1494 mImeiSv = (String)ar.result; 1495 break; 1496 1497 case EVENT_USSD: 1498 ar = (AsyncResult)msg.obj; 1499 1500 String[] ussdResult = (String[]) ar.result; 1501 1502 if (ussdResult.length > 1) { 1503 try { 1504 onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]); 1505 } catch (NumberFormatException e) { 1506 Rlog.w(LOG_TAG, "error parsing USSD"); 1507 } 1508 } 1509 break; 1510 1511 case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: { 1512 // Some MMI requests (eg USSD) are not completed 1513 // within the course of a CommandsInterface request 1514 // If the radio shuts off or resets while one of these 1515 // is pending, we need to clean up. 1516 1517 for (int i = mPendingMMIs.size() - 1; i >= 0; i--) { 1518 if (mPendingMMIs.get(i).isPendingUSSD()) { 1519 mPendingMMIs.get(i).onUssdFinishedError(); 1520 } 1521 } 1522 ImsPhone imsPhone = mImsPhone; 1523 if (imsPhone != null) { 1524 imsPhone.getServiceState().setStateOff(); 1525 } 1526 mRadioOffOrNotAvailableRegistrants.notifyRegistrants(); 1527 break; 1528 } 1529 1530 case EVENT_SSN: 1531 ar = (AsyncResult)msg.obj; 1532 SuppServiceNotification not = (SuppServiceNotification) ar.result; 1533 mSsnRegistrants.notifyRegistrants(ar); 1534 break; 1535 1536 case EVENT_SET_CALL_FORWARD_DONE: 1537 ar = (AsyncResult)msg.obj; 1538 IccRecords r = mIccRecords.get(); 1539 Cfu cfu = (Cfu) ar.userObj; 1540 if (ar.exception == null && r != null) { 1541 r.setVoiceCallForwardingFlag(1, msg.arg1 == 1, cfu.mSetCfNumber); 1542 } 1543 if (cfu.mOnComplete != null) { 1544 AsyncResult.forMessage(cfu.mOnComplete, ar.result, ar.exception); 1545 cfu.mOnComplete.sendToTarget(); 1546 } 1547 break; 1548 1549 case EVENT_SET_VM_NUMBER_DONE: 1550 ar = (AsyncResult)msg.obj; 1551 if (IccVmNotSupportedException.class.isInstance(ar.exception)) { 1552 storeVoiceMailNumber(mVmNumber); 1553 ar.exception = null; 1554 } 1555 onComplete = (Message) ar.userObj; 1556 if (onComplete != null) { 1557 AsyncResult.forMessage(onComplete, ar.result, ar.exception); 1558 onComplete.sendToTarget(); 1559 } 1560 break; 1561 1562 1563 case EVENT_GET_CALL_FORWARD_DONE: 1564 ar = (AsyncResult)msg.obj; 1565 if (ar.exception == null) { 1566 handleCfuQueryResult((CallForwardInfo[])ar.result); 1567 } 1568 onComplete = (Message) ar.userObj; 1569 if (onComplete != null) { 1570 AsyncResult.forMessage(onComplete, ar.result, ar.exception); 1571 onComplete.sendToTarget(); 1572 } 1573 break; 1574 1575 case EVENT_SET_NETWORK_AUTOMATIC: 1576 // Automatic network selection from EF_CSP SIM record 1577 ar = (AsyncResult) msg.obj; 1578 if (mSST.mSS.getIsManualSelection()) { 1579 setNetworkSelectionModeAutomatic((Message) ar.result); 1580 Rlog.d(LOG_TAG, "SET_NETWORK_SELECTION_AUTOMATIC: set to automatic"); 1581 } else { 1582 // prevent duplicate request which will push current PLMN to low priority 1583 Rlog.d(LOG_TAG, "SET_NETWORK_SELECTION_AUTOMATIC: already automatic, ignore"); 1584 } 1585 break; 1586 1587 case EVENT_ICC_RECORD_EVENTS: 1588 ar = (AsyncResult)msg.obj; 1589 processIccRecordEvents((Integer)ar.result); 1590 break; 1591 1592 case EVENT_SET_CLIR_COMPLETE: 1593 ar = (AsyncResult)msg.obj; 1594 if (ar.exception == null) { 1595 saveClirSetting(msg.arg1); 1596 } 1597 onComplete = (Message) ar.userObj; 1598 if (onComplete != null) { 1599 AsyncResult.forMessage(onComplete, ar.result, ar.exception); 1600 onComplete.sendToTarget(); 1601 } 1602 break; 1603 1604 case EVENT_SS: 1605 ar = (AsyncResult)msg.obj; 1606 Rlog.d(LOG_TAG, "Event EVENT_SS received"); 1607 // SS data is already being handled through MMI codes. 1608 // So, this result if processed as MMI response would help 1609 // in re-using the existing functionality. 1610 GsmMmiCode mmi = new GsmMmiCode(this, mUiccApplication.get()); 1611 mmi.processSsData(ar); 1612 break; 1613 1614 default: 1615 super.handleMessage(msg); 1616 } 1617 } 1618 1619 protected UiccCardApplication getUiccCardApplication() { 1620 return mUiccController.getUiccCardApplication(mPhoneId, 1621 UiccController.APP_FAM_3GPP); 1622 } 1623 1624 @Override 1625 protected void onUpdateIccAvailability() { 1626 if (mUiccController == null ) { 1627 return; 1628 } 1629 1630 UiccCardApplication newUiccApplication = 1631 mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_IMS); 1632 IsimUiccRecords newIsimUiccRecords = null; 1633 1634 if (newUiccApplication != null) { 1635 newIsimUiccRecords = (IsimUiccRecords)newUiccApplication.getIccRecords(); 1636 if (LOCAL_DEBUG) log("New ISIM application found"); 1637 } 1638 mIsimUiccRecords = newIsimUiccRecords; 1639 1640 newUiccApplication = getUiccCardApplication(); 1641 1642 UiccCardApplication app = mUiccApplication.get(); 1643 if (app != newUiccApplication) { 1644 if (app != null) { 1645 if (LOCAL_DEBUG) log("Removing stale icc objects."); 1646 if (mIccRecords.get() != null) { 1647 unregisterForSimRecordEvents(); 1648 mSimPhoneBookIntManager.updateIccRecords(null); 1649 } 1650 mIccRecords.set(null); 1651 mUiccApplication.set(null); 1652 } 1653 if (newUiccApplication != null) { 1654 if (LOCAL_DEBUG) log("New Uicc application found"); 1655 mUiccApplication.set(newUiccApplication); 1656 mIccRecords.set(newUiccApplication.getIccRecords()); 1657 registerForSimRecordEvents(); 1658 mSimPhoneBookIntManager.updateIccRecords(mIccRecords.get()); 1659 } 1660 } 1661 } 1662 1663 private void processIccRecordEvents(int eventCode) { 1664 switch (eventCode) { 1665 case IccRecords.EVENT_CFI: 1666 notifyCallForwardingIndicator(); 1667 break; 1668 } 1669 } 1670 1671 /** 1672 * Sets the "current" field in the telephony provider according to the SIM's operator 1673 * 1674 * @return true for success; false otherwise. 1675 */ 1676 public boolean updateCurrentCarrierInProvider() { 1677 long currentDds = SubscriptionManager.getDefaultDataSubId(); 1678 String operatorNumeric = getOperatorNumeric(); 1679 1680 log("updateCurrentCarrierInProvider: mSubId = " + getSubId() 1681 + " currentDds = " + currentDds + " operatorNumeric = " + operatorNumeric); 1682 1683 if (!TextUtils.isEmpty(operatorNumeric) && (getSubId() == currentDds)) { 1684 try { 1685 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"); 1686 ContentValues map = new ContentValues(); 1687 map.put(Telephony.Carriers.NUMERIC, operatorNumeric); 1688 mContext.getContentResolver().insert(uri, map); 1689 return true; 1690 } catch (SQLException e) { 1691 Rlog.e(LOG_TAG, "Can't store current operator", e); 1692 } 1693 } 1694 return false; 1695 } 1696 1697 /** 1698 * Saves CLIR setting so that we can re-apply it as necessary 1699 * (in case the RIL resets it across reboots). 1700 */ 1701 public void saveClirSetting(int commandInterfaceCLIRMode) { 1702 // open the shared preferences editor, and write the value. 1703 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); 1704 SharedPreferences.Editor editor = sp.edit(); 1705 editor.putInt(CLIR_KEY + getPhoneId(), commandInterfaceCLIRMode); 1706 1707 // commit and log the result. 1708 if (! editor.commit()) { 1709 Rlog.e(LOG_TAG, "failed to commit CLIR preference"); 1710 } 1711 } 1712 1713 private void handleCfuQueryResult(CallForwardInfo[] infos) { 1714 IccRecords r = mIccRecords.get(); 1715 if (r != null) { 1716 if (infos == null || infos.length == 0) { 1717 // Assume the default is not active 1718 // Set unconditional CFF in SIM to false 1719 r.setVoiceCallForwardingFlag(1, false, null); 1720 } else { 1721 for (int i = 0, s = infos.length; i < s; i++) { 1722 if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) { 1723 r.setVoiceCallForwardingFlag(1, (infos[i].status == 1), 1724 infos[i].number); 1725 // should only have the one 1726 break; 1727 } 1728 } 1729 } 1730 } 1731 } 1732 1733 /** 1734 * Retrieves the PhoneSubInfo of the GSMPhone 1735 */ 1736 @Override 1737 public PhoneSubInfo getPhoneSubInfo(){ 1738 return mSubInfo; 1739 } 1740 1741 /** 1742 * Retrieves the IccPhoneBookInterfaceManager of the GSMPhone 1743 */ 1744 @Override 1745 public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ 1746 return mSimPhoneBookIntManager; 1747 } 1748 1749 /** 1750 * Activate or deactivate cell broadcast SMS. 1751 * 1752 * @param activate 0 = activate, 1 = deactivate 1753 * @param response Callback message is empty on completion 1754 */ 1755 @Override 1756 public void activateCellBroadcastSms(int activate, Message response) { 1757 Rlog.e(LOG_TAG, "[GSMPhone] activateCellBroadcastSms() is obsolete; use SmsManager"); 1758 response.sendToTarget(); 1759 } 1760 1761 /** 1762 * Query the current configuration of cdma cell broadcast SMS. 1763 * 1764 * @param response Callback message is empty on completion 1765 */ 1766 @Override 1767 public void getCellBroadcastSmsConfig(Message response) { 1768 Rlog.e(LOG_TAG, "[GSMPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager"); 1769 response.sendToTarget(); 1770 } 1771 1772 /** 1773 * Configure cdma cell broadcast SMS. 1774 * 1775 * @param response Callback message is empty on completion 1776 */ 1777 @Override 1778 public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) { 1779 Rlog.e(LOG_TAG, "[GSMPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager"); 1780 response.sendToTarget(); 1781 } 1782 1783 @Override 1784 public boolean isCspPlmnEnabled() { 1785 IccRecords r = mIccRecords.get(); 1786 return (r != null) ? r.isCspPlmnEnabled() : false; 1787 } 1788 1789 boolean isManualNetSelAllowed() { 1790 1791 int nwMode = Phone.PREFERRED_NT_MODE; 1792 int subId = getSubId(); 1793 1794 nwMode = android.provider.Settings.Global.getInt(mContext.getContentResolver(), 1795 android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, nwMode); 1796 1797 Rlog.d(LOG_TAG, "isManualNetSelAllowed in mode = " + nwMode); 1798 /* 1799 * For multimode targets in global mode manual network 1800 * selection is disallowed 1801 */ 1802 if (isManualSelProhibitedInGlobalMode() 1803 && ((nwMode == Phone.NT_MODE_LTE_CDMA_EVDO_GSM_WCDMA) 1804 || (nwMode == Phone.NT_MODE_GLOBAL)) ){ 1805 Rlog.d(LOG_TAG, "Manual selection not supported in mode = " + nwMode); 1806 return false; 1807 } else { 1808 Rlog.d(LOG_TAG, "Manual selection is supported in mode = " + nwMode); 1809 } 1810 1811 /* 1812 * Single mode phone with - GSM network modes/global mode 1813 * LTE only for 3GPP 1814 * LTE centric + 3GPP Legacy 1815 * Note: the actual enabling/disabling manual selection for these 1816 * cases will be controlled by csp 1817 */ 1818 return true; 1819 } 1820 1821 private boolean isManualSelProhibitedInGlobalMode() { 1822 boolean isProhibited = false; 1823 final String configString = getContext().getResources().getString(com.android.internal. 1824 R.string.prohibit_manual_network_selection_in_gobal_mode); 1825 1826 if (!TextUtils.isEmpty(configString)) { 1827 String[] configArray = configString.split(";"); 1828 1829 if (configArray != null && 1830 ((configArray.length == 1 && configArray[0].equalsIgnoreCase("true")) || 1831 (configArray.length == 2 && !TextUtils.isEmpty(configArray[1]) && 1832 configArray[0].equalsIgnoreCase("true") && 1833 configArray[1].equalsIgnoreCase(getGroupIdLevel1())))) { 1834 isProhibited = true; 1835 } 1836 } 1837 Rlog.d(LOG_TAG, "isManualNetSelAllowedInGlobal in current carrier is " + isProhibited); 1838 return isProhibited; 1839 } 1840 1841 private void registerForSimRecordEvents() { 1842 IccRecords r = mIccRecords.get(); 1843 if (r == null) { 1844 return; 1845 } 1846 r.registerForNetworkSelectionModeAutomatic( 1847 this, EVENT_SET_NETWORK_AUTOMATIC, null); 1848 r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null); 1849 r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); 1850 } 1851 1852 private void unregisterForSimRecordEvents() { 1853 IccRecords r = mIccRecords.get(); 1854 if (r == null) { 1855 return; 1856 } 1857 r.unregisterForNetworkSelectionModeAutomatic(this); 1858 r.unregisterForRecordsEvents(this); 1859 r.unregisterForRecordsLoaded(this); 1860 } 1861 1862 @Override 1863 public void exitEmergencyCallbackMode() { 1864 if (mImsPhone != null) { 1865 mImsPhone.exitEmergencyCallbackMode(); 1866 } 1867 } 1868 1869 @Override 1870 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1871 pw.println("GSMPhone extends:"); 1872 super.dump(fd, pw, args); 1873 pw.println(" mCT=" + mCT); 1874 pw.println(" mSST=" + mSST); 1875 pw.println(" mPendingMMIs=" + mPendingMMIs); 1876 pw.println(" mSimPhoneBookIntManager=" + mSimPhoneBookIntManager); 1877 pw.println(" mSubInfo=" + mSubInfo); 1878 if (VDBG) pw.println(" mImei=" + mImei); 1879 if (VDBG) pw.println(" mImeiSv=" + mImeiSv); 1880 pw.println(" mVmNumber=" + mVmNumber); 1881 } 1882 1883 @Override 1884 public boolean setOperatorBrandOverride(String brand) { 1885 if (mUiccController == null) { 1886 return false; 1887 } 1888 1889 UiccCard card = mUiccController.getUiccCard(getPhoneId()); 1890 if (card == null) { 1891 return false; 1892 } 1893 1894 boolean status = card.setOperatorBrandOverride(brand); 1895 1896 // Refresh. 1897 if (status) { 1898 IccRecords iccRecords = mIccRecords.get(); 1899 if (iccRecords != null) { 1900 TelephonyManager.from(mContext).setSimOperatorNameForPhone( 1901 getPhoneId(), iccRecords.getServiceProviderName()); 1902 } 1903 if (mSST != null) { 1904 mSST.pollState(); 1905 } 1906 } 1907 return status; 1908 } 1909 1910 /** 1911 * @return operator numeric. 1912 */ 1913 public String getOperatorNumeric() { 1914 String operatorNumeric = null; 1915 IccRecords r = mIccRecords.get(); 1916 if (r != null) { 1917 operatorNumeric = r.getOperatorNumeric(); 1918 } 1919 return operatorNumeric; 1920 } 1921 1922 public void registerForAllDataDisconnected(Handler h, int what, Object obj) { 1923 ((DcTracker)mDcTracker) 1924 .registerForAllDataDisconnected(h, what, obj); 1925 } 1926 1927 public void unregisterForAllDataDisconnected(Handler h) { 1928 ((DcTracker)mDcTracker).unregisterForAllDataDisconnected(h); 1929 } 1930 1931 public void setInternalDataEnabled(boolean enable, Message onCompleteMsg) { 1932 ((DcTracker)mDcTracker) 1933 .setInternalDataEnabled(enable, onCompleteMsg); 1934 } 1935 1936 1937 public boolean setInternalDataEnabledFlag(boolean enable) { 1938 return ((DcTracker)mDcTracker) 1939 .setInternalDataEnabledFlag(enable); 1940 } 1941 1942 public void notifyEcbmTimerReset(Boolean flag) { 1943 mEcmTimerResetRegistrants.notifyResult(flag); 1944 } 1945 1946 /** 1947 * Registration point for Ecm timer reset 1948 * 1949 * @param h handler to notify 1950 * @param what User-defined message code 1951 * @param obj placed in Message.obj 1952 */ 1953 @Override 1954 public void registerForEcmTimerReset(Handler h, int what, Object obj) { 1955 mEcmTimerResetRegistrants.addUnique(h, what, obj); 1956 } 1957 1958 @Override 1959 public void unregisterForEcmTimerReset(Handler h) { 1960 mEcmTimerResetRegistrants.remove(h); 1961 } 1962 1963 /** 1964 * Sets the SIM voice message waiting indicator records. 1965 * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported 1966 * @param countWaiting The number of messages waiting, if known. Use 1967 * -1 to indicate that an unknown number of 1968 * messages are waiting 1969 */ 1970 @Override 1971 public void setVoiceMessageWaiting(int line, int countWaiting) { 1972 IccRecords r = mIccRecords.get(); 1973 if (r != null) { 1974 r.setVoiceMessageWaiting(line, countWaiting); 1975 } else { 1976 log("SIM Records not found, MWI not updated"); 1977 } 1978 } 1979 1980 protected void log(String s) { 1981 Rlog.d(LOG_TAG, "[GSMPhone] " + s); 1982 } 1983} 1984