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