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