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