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