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