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