Home | History | Annotate | Download | only in imsphone
      1 /*
      2  * Copyright (C) 2013 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.imsphone;
     18 
     19 import android.app.ActivityManagerNative;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.os.AsyncResult;
     23 import android.os.Handler;
     24 import android.os.Message;
     25 import android.os.PowerManager;
     26 import android.os.Registrant;
     27 import android.os.RegistrantList;
     28 import android.os.PowerManager.WakeLock;
     29 import android.os.SystemProperties;
     30 import android.os.UserHandle;
     31 
     32 import android.telephony.PhoneNumberUtils;
     33 import android.telephony.ServiceState;
     34 import android.telephony.Rlog;
     35 import android.telephony.SubscriptionManager;
     36 import android.text.TextUtils;
     37 
     38 import com.android.ims.ImsCallForwardInfo;
     39 import com.android.ims.ImsCallProfile;
     40 import com.android.ims.ImsEcbm;
     41 import com.android.ims.ImsEcbmStateListener;
     42 import com.android.ims.ImsException;
     43 import com.android.ims.ImsReasonInfo;
     44 import com.android.ims.ImsSsInfo;
     45 import com.android.ims.ImsUtInterface;
     46 
     47 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOC;
     48 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOIC;
     49 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOICxH;
     50 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC;
     51 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAICr;
     52 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_ALL;
     53 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MO;
     54 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MT;
     55 
     56 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
     57 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
     58 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
     59 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
     60 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
     61 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
     62 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
     63 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
     64 import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
     65 import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
     66 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
     67 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_NONE;
     68 
     69 import com.android.internal.telephony.Call;
     70 import com.android.internal.telephony.CallForwardInfo;
     71 import com.android.internal.telephony.CallStateException;
     72 import com.android.internal.telephony.CallTracker;
     73 import com.android.internal.telephony.CommandException;
     74 import com.android.internal.telephony.CommandsInterface;
     75 import com.android.internal.telephony.Connection;
     76 import com.android.internal.telephony.Phone;
     77 import com.android.internal.telephony.PhoneBase;
     78 import com.android.internal.telephony.PhoneConstants;
     79 import com.android.internal.telephony.PhoneNotifier;
     80 import com.android.internal.telephony.TelephonyIntents;
     81 import com.android.internal.telephony.TelephonyProperties;
     82 import com.android.internal.telephony.cdma.CDMAPhone;
     83 import com.android.internal.telephony.gsm.GSMPhone;
     84 import com.android.internal.telephony.uicc.IccRecords;
     85 
     86 import java.util.ArrayList;
     87 import java.util.List;
     88 
     89 /**
     90  * {@hide}
     91  */
     92 public class ImsPhone extends ImsPhoneBase {
     93     private static final String LOG_TAG = "ImsPhone";
     94     private static final boolean DBG = true;
     95     private static final boolean VDBG = false; // STOPSHIP if true
     96 
     97     protected static final int EVENT_SET_CALL_BARRING_DONE          = EVENT_LAST + 1;
     98     protected static final int EVENT_GET_CALL_BARRING_DONE          = EVENT_LAST + 2;
     99     protected static final int EVENT_SET_CALL_WAITING_DONE          = EVENT_LAST + 3;
    100     protected static final int EVENT_GET_CALL_WAITING_DONE          = EVENT_LAST + 4;
    101 
    102     public static final String CS_FALLBACK = "cs_fallback";
    103 
    104     static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
    105     static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer
    106 
    107     // Default Emergency Callback Mode exit timer
    108     private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
    109 
    110     // Instance Variables
    111     PhoneBase mDefaultPhone;
    112     ImsPhoneCallTracker mCT;
    113     ArrayList <ImsPhoneMmiCode> mPendingMMIs = new ArrayList<ImsPhoneMmiCode>();
    114 
    115     Registrant mPostDialHandler;
    116     ServiceState mSS = new ServiceState();
    117 
    118     // To redial silently through GSM or CDMA when dialing through IMS fails
    119     private String mLastDialString;
    120 
    121     WakeLock mWakeLock;
    122     protected boolean mIsPhoneInEcmState;
    123 
    124     // mEcmExitRespRegistrant is informed after the phone has been exited the emergency
    125     // callback mode keep track of if phone is in emergency callback mode
    126     private Registrant mEcmExitRespRegistrant;
    127 
    128     private final RegistrantList mSilentRedialRegistrants = new RegistrantList();
    129 
    130     private boolean mImsRegistered = false;
    131     // A runnable which is used to automatically exit from Ecm after a period of time.
    132     private Runnable mExitEcmRunnable = new Runnable() {
    133         @Override
    134         public void run() {
    135             exitEmergencyCallbackMode();
    136         }
    137     };
    138 
    139     // Create Cf (Call forward) so that dialling number &
    140     // mIsCfu (true if reason is call forward unconditional)
    141     // mOnComplete (Message object passed by client) can be packed &
    142     // given as a single Cf object as user data to UtInterface.
    143     private static class Cf {
    144         final String mSetCfNumber;
    145         final Message mOnComplete;
    146         final boolean mIsCfu;
    147 
    148         Cf(String cfNumber, boolean isCfu, Message onComplete) {
    149             mSetCfNumber = cfNumber;
    150             mIsCfu = isCfu;
    151             mOnComplete = onComplete;
    152         }
    153     }
    154 
    155     // Constructors
    156 
    157     ImsPhone(Context context, PhoneNotifier notifier, Phone defaultPhone) {
    158         super("ImsPhone", context, notifier);
    159 
    160         mDefaultPhone = (PhoneBase) defaultPhone;
    161         mCT = new ImsPhoneCallTracker(this);
    162         mSS.setStateOff();
    163 
    164         mPhoneId = mDefaultPhone.getPhoneId();
    165 
    166         // This is needed to handle phone process crashes
    167         // Same property is used for both CDMA & IMS phone.
    168         mIsPhoneInEcmState = SystemProperties.getBoolean(
    169                 TelephonyProperties.PROPERTY_INECM_MODE, false);
    170 
    171         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    172         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
    173         mWakeLock.setReferenceCounted(false);
    174     }
    175 
    176     public void updateParentPhone(PhoneBase parentPhone) {
    177         // synchronization is managed at the PhoneBase scope (which calls this function)
    178         mDefaultPhone = parentPhone;
    179         mPhoneId = mDefaultPhone.getPhoneId();
    180     }
    181 
    182     @Override
    183     public void dispose() {
    184         Rlog.d(LOG_TAG, "dispose");
    185         // Nothing to dispose in PhoneBase
    186         //super.dispose();
    187         mPendingMMIs.clear();
    188         mCT.dispose();
    189 
    190         //Force all referenced classes to unregister their former registered events
    191     }
    192 
    193     @Override
    194     public void removeReferences() {
    195         Rlog.d(LOG_TAG, "removeReferences");
    196         super.removeReferences();
    197 
    198         mCT = null;
    199         mSS = null;
    200     }
    201 
    202     @Override
    203     public ServiceState
    204     getServiceState() {
    205         return mSS;
    206     }
    207 
    208     /* package */ void setServiceState(int state) {
    209         mSS.setState(state);
    210     }
    211 
    212     @Override
    213     public CallTracker getCallTracker() {
    214         return mCT;
    215     }
    216 
    217     @Override
    218     public List<? extends ImsPhoneMmiCode>
    219     getPendingMmiCodes() {
    220         return mPendingMMIs;
    221     }
    222 
    223 
    224     @Override
    225     public void
    226     acceptCall(int videoState) throws CallStateException {
    227         mCT.acceptCall(videoState);
    228     }
    229 
    230     @Override
    231     public void
    232     rejectCall() throws CallStateException {
    233         mCT.rejectCall();
    234     }
    235 
    236     @Override
    237     public void
    238     switchHoldingAndActive() throws CallStateException {
    239         mCT.switchWaitingOrHoldingAndActive();
    240     }
    241 
    242     @Override
    243     public boolean canConference() {
    244         return mCT.canConference();
    245     }
    246 
    247     public boolean canDial() {
    248         return mCT.canDial();
    249     }
    250 
    251     @Override
    252     public void conference() {
    253         mCT.conference();
    254     }
    255 
    256     @Override
    257     public void clearDisconnected() {
    258         mCT.clearDisconnected();
    259     }
    260 
    261     @Override
    262     public boolean canTransfer() {
    263         return mCT.canTransfer();
    264     }
    265 
    266     @Override
    267     public void explicitCallTransfer() {
    268         mCT.explicitCallTransfer();
    269     }
    270 
    271     @Override
    272     public ImsPhoneCall
    273     getForegroundCall() {
    274         return mCT.mForegroundCall;
    275     }
    276 
    277     @Override
    278     public ImsPhoneCall
    279     getBackgroundCall() {
    280         return mCT.mBackgroundCall;
    281     }
    282 
    283     @Override
    284     public ImsPhoneCall
    285     getRingingCall() {
    286         return mCT.mRingingCall;
    287     }
    288 
    289     private boolean handleCallDeflectionIncallSupplementaryService(
    290             String dialString) {
    291         if (dialString.length() > 1) {
    292             return false;
    293         }
    294 
    295         if (getRingingCall().getState() != ImsPhoneCall.State.IDLE) {
    296             if (DBG) Rlog.d(LOG_TAG, "MmiCode 0: rejectCall");
    297             try {
    298                 mCT.rejectCall();
    299             } catch (CallStateException e) {
    300                 if (DBG) Rlog.d(LOG_TAG, "reject failed", e);
    301                 notifySuppServiceFailed(Phone.SuppService.REJECT);
    302             }
    303         } else if (getBackgroundCall().getState() != ImsPhoneCall.State.IDLE) {
    304             if (DBG) Rlog.d(LOG_TAG, "MmiCode 0: hangupWaitingOrBackground");
    305             try {
    306                 mCT.hangup(getBackgroundCall());
    307             } catch (CallStateException e) {
    308                 if (DBG) Rlog.d(LOG_TAG, "hangup failed", e);
    309             }
    310         }
    311 
    312         return true;
    313     }
    314 
    315 
    316     private boolean handleCallWaitingIncallSupplementaryService(
    317             String dialString) {
    318         int len = dialString.length();
    319 
    320         if (len > 2) {
    321             return false;
    322         }
    323 
    324         ImsPhoneCall call = getForegroundCall();
    325 
    326         try {
    327             if (len > 1) {
    328                 if (DBG) Rlog.d(LOG_TAG, "not support 1X SEND");
    329                 notifySuppServiceFailed(Phone.SuppService.HANGUP);
    330             } else {
    331                 if (call.getState() != ImsPhoneCall.State.IDLE) {
    332                     if (DBG) Rlog.d(LOG_TAG, "MmiCode 1: hangup foreground");
    333                     mCT.hangup(call);
    334                 } else {
    335                     if (DBG) Rlog.d(LOG_TAG, "MmiCode 1: switchWaitingOrHoldingAndActive");
    336                     mCT.switchWaitingOrHoldingAndActive();
    337                 }
    338             }
    339         } catch (CallStateException e) {
    340             if (DBG) Rlog.d(LOG_TAG, "hangup failed", e);
    341             notifySuppServiceFailed(Phone.SuppService.HANGUP);
    342         }
    343 
    344         return true;
    345     }
    346 
    347     private boolean handleCallHoldIncallSupplementaryService(String dialString) {
    348         int len = dialString.length();
    349 
    350         if (len > 2) {
    351             return false;
    352         }
    353 
    354         ImsPhoneCall call = getForegroundCall();
    355 
    356         if (len > 1) {
    357             if (DBG) Rlog.d(LOG_TAG, "separate not supported");
    358             notifySuppServiceFailed(Phone.SuppService.SEPARATE);
    359         } else {
    360             try {
    361                 if (getRingingCall().getState() != ImsPhoneCall.State.IDLE) {
    362                     if (DBG) Rlog.d(LOG_TAG, "MmiCode 2: accept ringing call");
    363                     mCT.acceptCall(ImsCallProfile.CALL_TYPE_VOICE);
    364                 } else {
    365                     if (DBG) Rlog.d(LOG_TAG, "MmiCode 2: switchWaitingOrHoldingAndActive");
    366                     mCT.switchWaitingOrHoldingAndActive();
    367                 }
    368             } catch (CallStateException e) {
    369                 if (DBG) Rlog.d(LOG_TAG, "switch failed", e);
    370                 notifySuppServiceFailed(Phone.SuppService.SWITCH);
    371             }
    372         }
    373 
    374         return true;
    375     }
    376 
    377     private boolean handleMultipartyIncallSupplementaryService(
    378             String dialString) {
    379         if (dialString.length() > 1) {
    380             return false;
    381         }
    382 
    383         if (DBG) Rlog.d(LOG_TAG, "MmiCode 3: merge calls");
    384         conference();
    385         return true;
    386     }
    387 
    388     private boolean handleEctIncallSupplementaryService(String dialString) {
    389 
    390         int len = dialString.length();
    391 
    392         if (len != 1) {
    393             return false;
    394         }
    395 
    396         if (DBG) Rlog.d(LOG_TAG, "MmiCode 4: not support explicit call transfer");
    397         notifySuppServiceFailed(Phone.SuppService.TRANSFER);
    398         return true;
    399     }
    400 
    401     private boolean handleCcbsIncallSupplementaryService(String dialString) {
    402         if (dialString.length() > 1) {
    403             return false;
    404         }
    405 
    406         Rlog.i(LOG_TAG, "MmiCode 5: CCBS not supported!");
    407         // Treat it as an "unknown" service.
    408         notifySuppServiceFailed(Phone.SuppService.UNKNOWN);
    409         return true;
    410     }
    411 
    412     @Override
    413     public boolean handleInCallMmiCommands(String dialString) {
    414         if (!isInCall()) {
    415             return false;
    416         }
    417 
    418         if (TextUtils.isEmpty(dialString)) {
    419             return false;
    420         }
    421 
    422         boolean result = false;
    423         char ch = dialString.charAt(0);
    424         switch (ch) {
    425             case '0':
    426                 result = handleCallDeflectionIncallSupplementaryService(
    427                         dialString);
    428                 break;
    429             case '1':
    430                 result = handleCallWaitingIncallSupplementaryService(
    431                         dialString);
    432                 break;
    433             case '2':
    434                 result = handleCallHoldIncallSupplementaryService(dialString);
    435                 break;
    436             case '3':
    437                 result = handleMultipartyIncallSupplementaryService(dialString);
    438                 break;
    439             case '4':
    440                 result = handleEctIncallSupplementaryService(dialString);
    441                 break;
    442             case '5':
    443                 result = handleCcbsIncallSupplementaryService(dialString);
    444                 break;
    445             default:
    446                 break;
    447         }
    448 
    449         return result;
    450     }
    451 
    452     boolean isInCall() {
    453         ImsPhoneCall.State foregroundCallState = getForegroundCall().getState();
    454         ImsPhoneCall.State backgroundCallState = getBackgroundCall().getState();
    455         ImsPhoneCall.State ringingCallState = getRingingCall().getState();
    456 
    457        return (foregroundCallState.isAlive() ||
    458                backgroundCallState.isAlive() ||
    459                ringingCallState.isAlive());
    460     }
    461 
    462     void notifyNewRingingConnection(Connection c) {
    463         mDefaultPhone.notifyNewRingingConnectionP(c);
    464     }
    465 
    466 
    467     @Override
    468     public Connection
    469     dial(String dialString, int videoState) throws CallStateException {
    470         return dialInternal(dialString, videoState);
    471     }
    472 
    473     protected Connection dialInternal(String dialString, int videoState)
    474             throws CallStateException {
    475         // Need to make sure dialString gets parsed properly
    476         String newDialString = PhoneNumberUtils.stripSeparators(dialString);
    477 
    478         // handle in-call MMI first if applicable
    479         if (handleInCallMmiCommands(newDialString)) {
    480             return null;
    481         }
    482 
    483         if (mDefaultPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
    484             return mCT.dial(dialString, videoState);
    485         }
    486 
    487         // Only look at the Network portion for mmi
    488         String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
    489         ImsPhoneMmiCode mmi =
    490                 ImsPhoneMmiCode.newFromDialString(networkPortion, this);
    491         if (DBG) Rlog.d(LOG_TAG,
    492                 "dialing w/ mmi '" + mmi + "'...");
    493 
    494         if (mmi == null) {
    495             return mCT.dial(dialString, videoState);
    496         } else if (mmi.isTemporaryModeCLIR()) {
    497             return mCT.dial(mmi.getDialingNumber(), mmi.getCLIRMode(), videoState);
    498         } else if (!mmi.isSupportedOverImsPhone()) {
    499             // If the mmi is not supported by IMS service,
    500             // try to initiate dialing with default phone
    501             throw new CallStateException(CS_FALLBACK);
    502         } else {
    503             mPendingMMIs.add(mmi);
    504             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
    505             mmi.processCode();
    506 
    507             return null;
    508         }
    509     }
    510 
    511     @Override
    512     public void
    513     sendDtmf(char c) {
    514         if (!PhoneNumberUtils.is12Key(c)) {
    515             Rlog.e(LOG_TAG,
    516                     "sendDtmf called with invalid character '" + c + "'");
    517         } else {
    518             if (mCT.mState ==  PhoneConstants.State.OFFHOOK) {
    519                 mCT.sendDtmf(c, null);
    520             }
    521         }
    522     }
    523 
    524     @Override
    525     public void
    526     startDtmf(char c) {
    527         if (!(PhoneNumberUtils.is12Key(c) || (c >= 'A' && c <= 'D'))) {
    528             Rlog.e(LOG_TAG,
    529                     "startDtmf called with invalid character '" + c + "'");
    530         } else {
    531             mCT.startDtmf(c);
    532         }
    533     }
    534 
    535     @Override
    536     public void
    537     stopDtmf() {
    538         mCT.stopDtmf();
    539     }
    540 
    541     @Override
    542     public void setOnPostDialCharacter(Handler h, int what, Object obj) {
    543         mPostDialHandler = new Registrant(h, what, obj);
    544     }
    545 
    546     /*package*/ void notifyIncomingRing() {
    547         if (DBG) Rlog.d(LOG_TAG, "notifyIncomingRing");
    548         AsyncResult ar = new AsyncResult(null, null, null);
    549         sendMessage(obtainMessage(EVENT_CALL_RING, ar));
    550     }
    551 
    552     @Override
    553     public void setMute(boolean muted) {
    554         mCT.setMute(muted);
    555     }
    556 
    557     @Override
    558     public void setUiTTYMode(int uiTtyMode, Message onComplete) {
    559         mCT.setUiTTYMode(uiTtyMode, onComplete);
    560     }
    561 
    562     @Override
    563     public boolean getMute() {
    564         return mCT.getMute();
    565     }
    566 
    567     @Override
    568     public PhoneConstants.State getState() {
    569         return mCT.mState;
    570     }
    571 
    572     private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
    573         switch (commandInterfaceCFReason) {
    574         case CF_REASON_UNCONDITIONAL:
    575         case CF_REASON_BUSY:
    576         case CF_REASON_NO_REPLY:
    577         case CF_REASON_NOT_REACHABLE:
    578         case CF_REASON_ALL:
    579         case CF_REASON_ALL_CONDITIONAL:
    580             return true;
    581         default:
    582             return false;
    583         }
    584     }
    585 
    586     private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) {
    587         switch (commandInterfaceCFAction) {
    588         case CF_ACTION_DISABLE:
    589         case CF_ACTION_ENABLE:
    590         case CF_ACTION_REGISTRATION:
    591         case CF_ACTION_ERASURE:
    592             return true;
    593         default:
    594             return false;
    595         }
    596     }
    597 
    598     private  boolean isCfEnable(int action) {
    599         return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION);
    600     }
    601 
    602     private int getConditionFromCFReason(int reason) {
    603         switch(reason) {
    604             case CF_REASON_UNCONDITIONAL: return ImsUtInterface.CDIV_CF_UNCONDITIONAL;
    605             case CF_REASON_BUSY: return ImsUtInterface.CDIV_CF_BUSY;
    606             case CF_REASON_NO_REPLY: return ImsUtInterface.CDIV_CF_NO_REPLY;
    607             case CF_REASON_NOT_REACHABLE: return ImsUtInterface.CDIV_CF_NOT_REACHABLE;
    608             case CF_REASON_ALL: return ImsUtInterface.CDIV_CF_ALL;
    609             case CF_REASON_ALL_CONDITIONAL: return ImsUtInterface.CDIV_CF_ALL_CONDITIONAL;
    610             default:
    611                 break;
    612         }
    613 
    614         return ImsUtInterface.INVALID;
    615     }
    616 
    617     private int getCFReasonFromCondition(int condition) {
    618         switch(condition) {
    619             case ImsUtInterface.CDIV_CF_UNCONDITIONAL: return CF_REASON_UNCONDITIONAL;
    620             case ImsUtInterface.CDIV_CF_BUSY: return CF_REASON_BUSY;
    621             case ImsUtInterface.CDIV_CF_NO_REPLY: return CF_REASON_NO_REPLY;
    622             case ImsUtInterface.CDIV_CF_NOT_REACHABLE: return CF_REASON_NOT_REACHABLE;
    623             case ImsUtInterface.CDIV_CF_ALL: return CF_REASON_ALL;
    624             case ImsUtInterface.CDIV_CF_ALL_CONDITIONAL: return CF_REASON_ALL_CONDITIONAL;
    625             default:
    626                 break;
    627         }
    628 
    629         return CF_REASON_NOT_REACHABLE;
    630     }
    631 
    632     private int getActionFromCFAction(int action) {
    633         switch(action) {
    634             case CF_ACTION_DISABLE: return ImsUtInterface.ACTION_DEACTIVATION;
    635             case CF_ACTION_ENABLE: return ImsUtInterface.ACTION_ACTIVATION;
    636             case CF_ACTION_ERASURE: return ImsUtInterface.ACTION_ERASURE;
    637             case CF_ACTION_REGISTRATION: return ImsUtInterface.ACTION_REGISTRATION;
    638             default:
    639                 break;
    640         }
    641 
    642         return ImsUtInterface.INVALID;
    643     }
    644 
    645     @Override
    646     public void getCallForwardingOption(int commandInterfaceCFReason,
    647             Message onComplete) {
    648         if (DBG) Rlog.d(LOG_TAG, "getCallForwardingOption reason=" + commandInterfaceCFReason);
    649         if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
    650             if (DBG) Rlog.d(LOG_TAG, "requesting call forwarding query.");
    651             Message resp;
    652             resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete);
    653 
    654             try {
    655                 ImsUtInterface ut = mCT.getUtInterface();
    656                 ut.queryCallForward(getConditionFromCFReason(commandInterfaceCFReason),null,resp);
    657             } catch (ImsException e) {
    658                 sendErrorResponse(onComplete, e);
    659             }
    660         } else if (onComplete != null) {
    661             sendErrorResponse(onComplete);
    662         }
    663     }
    664 
    665     @Override
    666     public void setCallForwardingOption(int commandInterfaceCFAction,
    667             int commandInterfaceCFReason,
    668             String dialingNumber,
    669             int timerSeconds,
    670             Message onComplete) {
    671         if (DBG) Rlog.d(LOG_TAG, "setCallForwardingOption action=" + commandInterfaceCFAction
    672                 + ", reason=" + commandInterfaceCFReason);
    673         if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) &&
    674                 (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) {
    675             Message resp;
    676             Cf cf = new Cf(dialingNumber,
    677                     (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL ? true : false),
    678                     onComplete);
    679             resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE,
    680                     isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cf);
    681 
    682             try {
    683                 ImsUtInterface ut = mCT.getUtInterface();
    684                 ut.updateCallForward(getActionFromCFAction(commandInterfaceCFAction),
    685                         getConditionFromCFReason(commandInterfaceCFReason),
    686                         dialingNumber,
    687                         timerSeconds,
    688                         onComplete);
    689              } catch (ImsException e) {
    690                 sendErrorResponse(onComplete, e);
    691              }
    692         } else if (onComplete != null) {
    693             sendErrorResponse(onComplete);
    694         }
    695     }
    696 
    697     @Override
    698     public void getCallWaiting(Message onComplete) {
    699         if (DBG) Rlog.d(LOG_TAG, "getCallWaiting");
    700         Message resp;
    701         resp = obtainMessage(EVENT_GET_CALL_WAITING_DONE, onComplete);
    702 
    703         try {
    704             ImsUtInterface ut = mCT.getUtInterface();
    705             ut.queryCallWaiting(resp);
    706         } catch (ImsException e) {
    707             sendErrorResponse(onComplete, e);
    708         }
    709     }
    710 
    711     @Override
    712     public void setCallWaiting(boolean enable, Message onComplete) {
    713         if (DBG) Rlog.d(LOG_TAG, "setCallWaiting enable=" + enable);
    714         Message resp;
    715         resp = obtainMessage(EVENT_SET_CALL_WAITING_DONE, onComplete);
    716 
    717         try {
    718             ImsUtInterface ut = mCT.getUtInterface();
    719             ut.updateCallWaiting(enable, resp);
    720         } catch (ImsException e) {
    721             sendErrorResponse(onComplete, e);
    722         }
    723     }
    724 
    725     private int getCBTypeFromFacility(String facility) {
    726         if (CB_FACILITY_BAOC.equals(facility)) {
    727             return ImsUtInterface.CB_BAOC;
    728         } else if (CB_FACILITY_BAOIC.equals(facility)) {
    729             return ImsUtInterface.CB_BOIC;
    730         } else if (CB_FACILITY_BAOICxH.equals(facility)) {
    731             return ImsUtInterface.CB_BOIC_EXHC;
    732         } else if (CB_FACILITY_BAIC.equals(facility)) {
    733             return ImsUtInterface.CB_BAIC;
    734         } else if (CB_FACILITY_BAICr.equals(facility)) {
    735             return ImsUtInterface.CB_BIC_WR;
    736         } else if (CB_FACILITY_BA_ALL.equals(facility)) {
    737             return ImsUtInterface.CB_BA_ALL;
    738         } else if (CB_FACILITY_BA_MO.equals(facility)) {
    739             return ImsUtInterface.CB_BA_MO;
    740         } else if (CB_FACILITY_BA_MT.equals(facility)) {
    741             return ImsUtInterface.CB_BA_MT;
    742         }
    743 
    744         return 0;
    745     }
    746 
    747     /* package */
    748     void getCallBarring(String facility, Message onComplete) {
    749         if (DBG) Rlog.d(LOG_TAG, "getCallBarring facility=" + facility);
    750         Message resp;
    751         resp = obtainMessage(EVENT_GET_CALL_BARRING_DONE, onComplete);
    752 
    753         try {
    754             ImsUtInterface ut = mCT.getUtInterface();
    755             ut.queryCallBarring(getCBTypeFromFacility(facility), resp);
    756         } catch (ImsException e) {
    757             sendErrorResponse(onComplete, e);
    758         }
    759     }
    760 
    761     /* package */
    762     void setCallBarring(String facility, boolean lockState, String password, Message onComplete) {
    763         if (DBG) Rlog.d(LOG_TAG, "setCallBarring facility=" + facility
    764                 + ", lockState=" + lockState);
    765         Message resp;
    766         resp = obtainMessage(EVENT_SET_CALL_BARRING_DONE, onComplete);
    767 
    768         try {
    769             ImsUtInterface ut = mCT.getUtInterface();
    770             // password is not required with Ut interface
    771             ut.updateCallBarring(getCBTypeFromFacility(facility), lockState, resp, null);
    772         } catch (ImsException e) {
    773             sendErrorResponse(onComplete, e);
    774         }
    775     }
    776 
    777     @Override
    778     public void sendUssdResponse(String ussdMessge) {
    779         Rlog.d(LOG_TAG, "sendUssdResponse");
    780         ImsPhoneMmiCode mmi = ImsPhoneMmiCode.newFromUssdUserInput(ussdMessge, this);
    781         mPendingMMIs.add(mmi);
    782         mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
    783         mmi.sendUssd(ussdMessge);
    784     }
    785 
    786     /* package */
    787     void sendUSSD (String ussdString, Message response) {
    788         mCT.sendUSSD(ussdString, response);
    789     }
    790 
    791     /* package */
    792     void cancelUSSD() {
    793         mCT.cancelUSSD();
    794     }
    795 
    796     /* package */
    797     void sendErrorResponse(Message onComplete) {
    798         Rlog.d(LOG_TAG, "sendErrorResponse");
    799         if (onComplete != null) {
    800             AsyncResult.forMessage(onComplete, null,
    801                     new CommandException(CommandException.Error.GENERIC_FAILURE));
    802             onComplete.sendToTarget();
    803         }
    804     }
    805 
    806     /* package */
    807     void sendErrorResponse(Message onComplete, Throwable e) {
    808         Rlog.d(LOG_TAG, "sendErrorResponse");
    809         if (onComplete != null) {
    810             AsyncResult.forMessage(onComplete, null, getCommandException(e));
    811             onComplete.sendToTarget();
    812         }
    813     }
    814 
    815     /* package */
    816     void sendErrorResponse(Message onComplete, ImsReasonInfo reasonInfo) {
    817         Rlog.d(LOG_TAG, "sendErrorResponse reasonCode=" + reasonInfo.getCode());
    818         if (onComplete != null) {
    819             AsyncResult.forMessage(onComplete, null, getCommandException(reasonInfo.getCode()));
    820             onComplete.sendToTarget();
    821         }
    822     }
    823 
    824     /* package */
    825     CommandException getCommandException(int code) {
    826         Rlog.d(LOG_TAG, "getCommandException code=" + code);
    827         CommandException.Error error = CommandException.Error.GENERIC_FAILURE;
    828 
    829         switch(code) {
    830             case ImsReasonInfo.CODE_UT_NOT_SUPPORTED:
    831                 error = CommandException.Error.REQUEST_NOT_SUPPORTED;
    832                 break;
    833             case ImsReasonInfo.CODE_UT_CB_PASSWORD_MISMATCH:
    834                 error = CommandException.Error.PASSWORD_INCORRECT;
    835                 break;
    836             default:
    837                 break;
    838         }
    839 
    840         return new CommandException(error);
    841     }
    842 
    843     /* package */
    844     CommandException getCommandException(Throwable e) {
    845         CommandException ex = null;
    846 
    847         if (e instanceof ImsException) {
    848             ex = getCommandException(((ImsException)e).getCode());
    849         } else {
    850             Rlog.d(LOG_TAG, "getCommandException generic failure");
    851             ex = new CommandException(CommandException.Error.GENERIC_FAILURE);
    852         }
    853         return ex;
    854     }
    855 
    856     private void
    857     onNetworkInitiatedUssd(ImsPhoneMmiCode mmi) {
    858         Rlog.d(LOG_TAG, "onNetworkInitiatedUssd");
    859         mMmiCompleteRegistrants.notifyRegistrants(
    860             new AsyncResult(null, mmi, null));
    861     }
    862 
    863     /* package */
    864     void onIncomingUSSD (int ussdMode, String ussdMessage) {
    865         if (DBG) Rlog.d(LOG_TAG, "onIncomingUSSD ussdMode=" + ussdMode);
    866 
    867         boolean isUssdError;
    868         boolean isUssdRequest;
    869 
    870         isUssdRequest
    871             = (ussdMode == CommandsInterface.USSD_MODE_REQUEST);
    872 
    873         isUssdError
    874             = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY
    875                 && ussdMode != CommandsInterface.USSD_MODE_REQUEST);
    876 
    877         ImsPhoneMmiCode found = null;
    878         for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
    879             if(mPendingMMIs.get(i).isPendingUSSD()) {
    880                 found = mPendingMMIs.get(i);
    881                 break;
    882             }
    883         }
    884 
    885         if (found != null) {
    886             // Complete pending USSD
    887             if (isUssdError) {
    888                 found.onUssdFinishedError();
    889             } else {
    890                 found.onUssdFinished(ussdMessage, isUssdRequest);
    891             }
    892         } else { // pending USSD not found
    893             // The network may initiate its own USSD request
    894 
    895             // ignore everything that isnt a Notify or a Request
    896             // also, discard if there is no message to present
    897             if (!isUssdError && ussdMessage != null) {
    898                 ImsPhoneMmiCode mmi;
    899                 mmi = ImsPhoneMmiCode.newNetworkInitiatedUssd(ussdMessage,
    900                         isUssdRequest,
    901                         ImsPhone.this);
    902                 onNetworkInitiatedUssd(mmi);
    903             }
    904         }
    905     }
    906 
    907     /**
    908      * Removes the given MMI from the pending list and notifies
    909      * registrants that it is complete.
    910      * @param mmi MMI that is done
    911      */
    912     /*package*/ void
    913     onMMIDone(ImsPhoneMmiCode mmi) {
    914         /* Only notify complete if it's on the pending list.
    915          * Otherwise, it's already been handled (eg, previously canceled).
    916          * The exception is cancellation of an incoming USSD-REQUEST, which is
    917          * not on the list.
    918          */
    919         if (mPendingMMIs.remove(mmi) || mmi.isUssdRequest()) {
    920             mMmiCompleteRegistrants.notifyRegistrants(
    921                     new AsyncResult(null, mmi, null));
    922         }
    923     }
    924 
    925     public ArrayList<Connection> getHandoverConnection() {
    926         ArrayList<Connection> connList = new ArrayList<Connection>();
    927         // Add all foreground call connections
    928         connList.addAll(getForegroundCall().mConnections);
    929         // Add all background call connections
    930         connList.addAll(getBackgroundCall().mConnections);
    931         // Add all background call connections
    932         connList.addAll(getRingingCall().mConnections);
    933         if (connList.size() > 0) {
    934             return connList;
    935         } else {
    936             return null;
    937         }
    938     }
    939 
    940     public void notifySrvccState(Call.SrvccState state) {
    941         mCT.notifySrvccState(state);
    942     }
    943 
    944     /* package */ void
    945     initiateSilentRedial() {
    946         String result = mLastDialString;
    947         AsyncResult ar = new AsyncResult(null, result, null);
    948         if (ar != null) {
    949             mSilentRedialRegistrants.notifyRegistrants(ar);
    950         }
    951     }
    952 
    953     public void registerForSilentRedial(Handler h, int what, Object obj) {
    954         mSilentRedialRegistrants.addUnique(h, what, obj);
    955     }
    956 
    957     public void unregisterForSilentRedial(Handler h) {
    958         mSilentRedialRegistrants.remove(h);
    959     }
    960 
    961     @Override
    962     public int getSubId() {
    963         return mDefaultPhone.getSubId();
    964     }
    965 
    966     @Override
    967     public int getPhoneId() {
    968         return mDefaultPhone.getPhoneId();
    969     }
    970 
    971     private IccRecords getIccRecords() {
    972         return mDefaultPhone.mIccRecords.get();
    973     }
    974 
    975     private CallForwardInfo getCallForwardInfo(ImsCallForwardInfo info) {
    976         CallForwardInfo cfInfo = new CallForwardInfo();
    977         cfInfo.status = info.mStatus;
    978         cfInfo.reason = getCFReasonFromCondition(info.mCondition);
    979         cfInfo.serviceClass = SERVICE_CLASS_VOICE;
    980         cfInfo.toa = info.mToA;
    981         cfInfo.number = info.mNumber;
    982         cfInfo.timeSeconds = info.mTimeSeconds;
    983         return cfInfo;
    984     }
    985 
    986     private CallForwardInfo[] handleCfQueryResult(ImsCallForwardInfo[] infos) {
    987         CallForwardInfo[] cfInfos = null;
    988 
    989         if (infos != null && infos.length != 0) {
    990             cfInfos = new CallForwardInfo[infos.length];
    991         }
    992 
    993         IccRecords r = getIccRecords();
    994         if (infos == null || infos.length == 0) {
    995             if (r != null) {
    996                 // Assume the default is not active
    997                 // Set unconditional CFF in SIM to false
    998                 r.setVoiceCallForwardingFlag(1, false, null);
    999             }
   1000         } else {
   1001             for (int i = 0, s = infos.length; i < s; i++) {
   1002                 if (infos[i].mCondition == ImsUtInterface.CDIV_CF_UNCONDITIONAL) {
   1003                     if (r != null) {
   1004                         r.setVoiceCallForwardingFlag(1, (infos[i].mStatus == 1),
   1005                             infos[i].mNumber);
   1006                     }
   1007                 }
   1008                 cfInfos[i] = getCallForwardInfo(infos[i]);
   1009             }
   1010         }
   1011 
   1012         return cfInfos;
   1013     }
   1014 
   1015     private int[] handleCbQueryResult(ImsSsInfo[] infos) {
   1016         int[] cbInfos = new int[1];
   1017         cbInfos[0] = SERVICE_CLASS_NONE;
   1018 
   1019         if (infos[0].mStatus == 1) {
   1020             cbInfos[0] = SERVICE_CLASS_VOICE;
   1021         }
   1022 
   1023         return cbInfos;
   1024     }
   1025 
   1026     private int[] handleCwQueryResult(ImsSsInfo[] infos) {
   1027         int[] cwInfos = new int[2];
   1028         cwInfos[0] = 0;
   1029 
   1030         if (infos[0].mStatus == 1) {
   1031             cwInfos[0] = 1;
   1032             cwInfos[1] = SERVICE_CLASS_VOICE;
   1033         }
   1034 
   1035         return cwInfos;
   1036     }
   1037 
   1038     private void
   1039     sendResponse(Message onComplete, Object result, Throwable e) {
   1040         if (onComplete != null) {
   1041             CommandException ex = null;
   1042             ImsException imsEx = null;
   1043             if (e != null) {
   1044                 if (e instanceof ImsException) {
   1045                     imsEx = (ImsException) e;
   1046                     AsyncResult.forMessage(onComplete, result, imsEx);
   1047                 } else {
   1048                     ex = getCommandException(e);
   1049                     AsyncResult.forMessage(onComplete, result, ex);
   1050                 }
   1051             } else {
   1052                 AsyncResult.forMessage(onComplete, result, null);
   1053             }
   1054             onComplete.sendToTarget();
   1055         }
   1056     }
   1057 
   1058     @Override
   1059     public void handleMessage (Message msg) {
   1060         AsyncResult ar = (AsyncResult) msg.obj;
   1061         Message onComplete;
   1062 
   1063         if (DBG) Rlog.d(LOG_TAG, "handleMessage what=" + msg.what);
   1064         switch (msg.what) {
   1065             case EVENT_SET_CALL_FORWARD_DONE:
   1066                 IccRecords r = getIccRecords();
   1067                 Cf cf = (Cf) ar.userObj;
   1068                 if (cf.mIsCfu && ar.exception == null && r != null) {
   1069                     r.setVoiceCallForwardingFlag(1, msg.arg1 == 1, cf.mSetCfNumber);
   1070                 }
   1071                 sendResponse(cf.mOnComplete, null, ar.exception);
   1072                 break;
   1073 
   1074             case EVENT_GET_CALL_FORWARD_DONE:
   1075                 CallForwardInfo[] cfInfos = null;
   1076                 if (ar.exception == null) {
   1077                     cfInfos = handleCfQueryResult((ImsCallForwardInfo[])ar.result);
   1078                 }
   1079                 sendResponse((Message) ar.userObj, cfInfos, ar.exception);
   1080                 break;
   1081 
   1082              case EVENT_GET_CALL_BARRING_DONE:
   1083              case EVENT_GET_CALL_WAITING_DONE:
   1084                 int[] ssInfos = null;
   1085                 if (ar.exception == null) {
   1086                     if (msg.what == EVENT_GET_CALL_BARRING_DONE) {
   1087                         ssInfos = handleCbQueryResult((ImsSsInfo[])ar.result);
   1088                     } else if (msg.what == EVENT_GET_CALL_WAITING_DONE) {
   1089                         ssInfos = handleCwQueryResult((ImsSsInfo[])ar.result);
   1090                     }
   1091                 }
   1092                 sendResponse((Message) ar.userObj, ssInfos, ar.exception);
   1093                 break;
   1094 
   1095              case EVENT_SET_CALL_BARRING_DONE:
   1096              case EVENT_SET_CALL_WAITING_DONE:
   1097                 sendResponse((Message) ar.userObj, null, ar.exception);
   1098                 break;
   1099 
   1100              default:
   1101                  super.handleMessage(msg);
   1102                  break;
   1103         }
   1104     }
   1105 
   1106     /**
   1107      * Listen to the IMS ECBM state change
   1108      */
   1109     ImsEcbmStateListener mImsEcbmStateListener =
   1110             new ImsEcbmStateListener() {
   1111                 @Override
   1112                 public void onECBMEntered() {
   1113                     if (DBG) Rlog.d(LOG_TAG, "onECBMEntered");
   1114                     handleEnterEmergencyCallbackMode();
   1115                 }
   1116 
   1117                 @Override
   1118                 public void onECBMExited() {
   1119                     if (DBG) Rlog.d(LOG_TAG, "onECBMExited");
   1120                     handleExitEmergencyCallbackMode();
   1121                 }
   1122             };
   1123 
   1124     public boolean isInEmergencyCall() {
   1125         return mCT.isInEmergencyCall();
   1126     }
   1127 
   1128     public boolean isInEcm() {
   1129         return mIsPhoneInEcmState;
   1130     }
   1131 
   1132     void sendEmergencyCallbackModeChange() {
   1133         // Send an Intent
   1134         Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
   1135         intent.putExtra(PhoneConstants.PHONE_IN_ECM_STATE, mIsPhoneInEcmState);
   1136         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
   1137         ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
   1138         if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallbackModeChange");
   1139     }
   1140 
   1141     @Override
   1142     public void exitEmergencyCallbackMode() {
   1143         if (mWakeLock.isHeld()) {
   1144             mWakeLock.release();
   1145         }
   1146         if (DBG) Rlog.d(LOG_TAG, "exitEmergencyCallbackMode()");
   1147 
   1148         // Send a message which will invoke handleExitEmergencyCallbackMode
   1149         ImsEcbm ecbm;
   1150         try {
   1151             ecbm = mCT.getEcbmInterface();
   1152             ecbm.exitEmergencyCallbackMode();
   1153         } catch (ImsException e) {
   1154             e.printStackTrace();
   1155         }
   1156     }
   1157 
   1158     private void handleEnterEmergencyCallbackMode() {
   1159         if (DBG) {
   1160             Rlog.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= "
   1161                     + mIsPhoneInEcmState);
   1162         }
   1163         // if phone is not in Ecm mode, and it's changed to Ecm mode
   1164         if (mIsPhoneInEcmState == false) {
   1165             mIsPhoneInEcmState = true;
   1166             // notify change
   1167             sendEmergencyCallbackModeChange();
   1168             setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
   1169 
   1170             // Post this runnable so we will automatically exit
   1171             // if no one invokes exitEmergencyCallbackMode() directly.
   1172             long delayInMillis = SystemProperties.getLong(
   1173                     TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
   1174             postDelayed(mExitEcmRunnable, delayInMillis);
   1175             // We don't want to go to sleep while in Ecm
   1176             mWakeLock.acquire();
   1177         }
   1178     }
   1179 
   1180     private void handleExitEmergencyCallbackMode() {
   1181         if (DBG) {
   1182             Rlog.d(LOG_TAG, "handleExitEmergencyCallbackMode: mIsPhoneInEcmState = "
   1183                     + mIsPhoneInEcmState);
   1184         }
   1185         // Remove pending exit Ecm runnable, if any
   1186         removeCallbacks(mExitEcmRunnable);
   1187 
   1188         if (mEcmExitRespRegistrant != null) {
   1189             mEcmExitRespRegistrant.notifyResult(Boolean.TRUE);
   1190         }
   1191             if (mIsPhoneInEcmState) {
   1192                 mIsPhoneInEcmState = false;
   1193                 setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
   1194             }
   1195             // send an Intent
   1196             sendEmergencyCallbackModeChange();
   1197     }
   1198 
   1199     /**
   1200      * Handle to cancel or restart Ecm timer in emergency call back mode if action is
   1201      * CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled; otherwise, restart
   1202      * Ecm timer and notify apps the timer is restarted.
   1203      */
   1204     void handleTimerInEmergencyCallbackMode(int action) {
   1205         switch (action) {
   1206             case CANCEL_ECM_TIMER:
   1207                 removeCallbacks(mExitEcmRunnable);
   1208                 if (mDefaultPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {
   1209                     ((GSMPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.TRUE);
   1210                 } else { // Should be CDMA - also go here by default
   1211                     ((CDMAPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.TRUE);
   1212                 }
   1213                 break;
   1214             case RESTART_ECM_TIMER:
   1215                 long delayInMillis = SystemProperties.getLong(
   1216                         TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
   1217                 postDelayed(mExitEcmRunnable, delayInMillis);
   1218                 if (mDefaultPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {
   1219                     ((GSMPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.FALSE);
   1220                 } else { // Should be CDMA - also go here by default
   1221                     ((CDMAPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.FALSE);
   1222                 }
   1223                 break;
   1224             default:
   1225                 Rlog.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action);
   1226         }
   1227     }
   1228 
   1229     public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
   1230         mEcmExitRespRegistrant = new Registrant(h, what, obj);
   1231     }
   1232 
   1233     public void unsetOnEcbModeExitResponse(Handler h) {
   1234         mEcmExitRespRegistrant.clear();
   1235     }
   1236 
   1237     public boolean isVolteEnabled() {
   1238         return mCT.isVolteEnabled();
   1239     }
   1240 
   1241     public boolean isVtEnabled() {
   1242         return mCT.isVtEnabled();
   1243     }
   1244 
   1245     public Phone getDefaultPhone() {
   1246         return mDefaultPhone;
   1247     }
   1248 
   1249     public boolean isImsRegistered() {
   1250         return mImsRegistered;
   1251     }
   1252 
   1253     public void setImsRegistered(boolean value) {
   1254         mImsRegistered = value;
   1255     }
   1256 
   1257     public void callEndCleanupHandOverCallIfAny() {
   1258         mCT.callEndCleanupHandOverCallIfAny();
   1259     }
   1260 }
   1261