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