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