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