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