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