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