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