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