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