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