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