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