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