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