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