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