Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2010 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;
     18 
     19 import com.android.internal.telephony.imsphone.ImsPhone;
     20 import com.android.internal.telephony.sip.SipPhone;
     21 
     22 import android.content.Context;
     23 import android.os.AsyncResult;
     24 import android.os.Handler;
     25 import android.os.Message;
     26 import android.os.RegistrantList;
     27 import android.os.Registrant;
     28 import android.telecom.VideoProfile;
     29 import android.telephony.PhoneNumberUtils;
     30 import android.telephony.TelephonyManager;
     31 import android.telephony.PhoneStateListener;
     32 import android.telephony.ServiceState;
     33 import android.telephony.Rlog;
     34 
     35 import java.util.ArrayList;
     36 import java.util.Collections;
     37 import java.util.HashMap;
     38 import java.util.List;
     39 
     40 
     41 
     42 /**
     43  * @hide
     44  *
     45  * CallManager class provides an abstract layer for PhoneApp to access
     46  * and control calls. It implements Phone interface.
     47  *
     48  * CallManager provides call and connection control as well as
     49  * channel capability.
     50  *
     51  * There are three categories of APIs CallManager provided
     52  *
     53  *  1. Call control and operation, such as dial() and hangup()
     54  *  2. Channel capabilities, such as CanConference()
     55  *  3. Register notification
     56  *
     57  *
     58  */
     59 public final class CallManager {
     60 
     61     private static final String LOG_TAG ="CallManager";
     62     private static final boolean DBG = true;
     63     private static final boolean VDBG = false;
     64 
     65     private static final int EVENT_DISCONNECT = 100;
     66     private static final int EVENT_PRECISE_CALL_STATE_CHANGED = 101;
     67     private static final int EVENT_NEW_RINGING_CONNECTION = 102;
     68     private static final int EVENT_UNKNOWN_CONNECTION = 103;
     69     private static final int EVENT_INCOMING_RING = 104;
     70     private static final int EVENT_RINGBACK_TONE = 105;
     71     private static final int EVENT_IN_CALL_VOICE_PRIVACY_ON = 106;
     72     private static final int EVENT_IN_CALL_VOICE_PRIVACY_OFF = 107;
     73     private static final int EVENT_CALL_WAITING = 108;
     74     private static final int EVENT_DISPLAY_INFO = 109;
     75     private static final int EVENT_SIGNAL_INFO = 110;
     76     private static final int EVENT_CDMA_OTA_STATUS_CHANGE = 111;
     77     private static final int EVENT_RESEND_INCALL_MUTE = 112;
     78     private static final int EVENT_MMI_INITIATE = 113;
     79     private static final int EVENT_MMI_COMPLETE = 114;
     80     private static final int EVENT_ECM_TIMER_RESET = 115;
     81     private static final int EVENT_SUBSCRIPTION_INFO_READY = 116;
     82     private static final int EVENT_SUPP_SERVICE_FAILED = 117;
     83     private static final int EVENT_SERVICE_STATE_CHANGED = 118;
     84     private static final int EVENT_POST_DIAL_CHARACTER = 119;
     85     private static final int EVENT_ONHOLD_TONE = 120;
     86     // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
     87     //private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 121;
     88     private static final int EVENT_TTY_MODE_RECEIVED = 122;
     89 
     90     // Singleton instance
     91     private static final CallManager INSTANCE = new CallManager();
     92 
     93     // list of registered phones, which are PhoneBase objs
     94     private final ArrayList<Phone> mPhones;
     95 
     96     // list of supported ringing calls
     97     private final ArrayList<Call> mRingingCalls;
     98 
     99     // list of supported background calls
    100     private final ArrayList<Call> mBackgroundCalls;
    101 
    102     // list of supported foreground calls
    103     private final ArrayList<Call> mForegroundCalls;
    104 
    105     // empty connection list
    106     private final ArrayList<Connection> mEmptyConnections = new ArrayList<Connection>();
    107 
    108     // mapping of phones to registered handler instances used for callbacks from RIL
    109     private final HashMap<Phone, CallManagerHandler> mHandlerMap = new HashMap<>();
    110 
    111     // default phone as the first phone registered, which is PhoneBase obj
    112     private Phone mDefaultPhone;
    113 
    114     private boolean mSpeedUpAudioForMtCall = false;
    115     // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
    116     //private boolean mIsEccDialing = false;
    117 
    118     // state registrants
    119     protected final RegistrantList mPreciseCallStateRegistrants
    120     = new RegistrantList();
    121 
    122     protected final RegistrantList mNewRingingConnectionRegistrants
    123     = new RegistrantList();
    124 
    125     protected final RegistrantList mIncomingRingRegistrants
    126     = new RegistrantList();
    127 
    128     protected final RegistrantList mDisconnectRegistrants
    129     = new RegistrantList();
    130 
    131     protected final RegistrantList mMmiRegistrants
    132     = new RegistrantList();
    133 
    134     protected final RegistrantList mUnknownConnectionRegistrants
    135     = new RegistrantList();
    136 
    137     protected final RegistrantList mRingbackToneRegistrants
    138     = new RegistrantList();
    139 
    140     protected final RegistrantList mOnHoldToneRegistrants
    141     = new RegistrantList();
    142 
    143     protected final RegistrantList mInCallVoicePrivacyOnRegistrants
    144     = new RegistrantList();
    145 
    146     protected final RegistrantList mInCallVoicePrivacyOffRegistrants
    147     = new RegistrantList();
    148 
    149     protected final RegistrantList mCallWaitingRegistrants
    150     = new RegistrantList();
    151 
    152     protected final RegistrantList mDisplayInfoRegistrants
    153     = new RegistrantList();
    154 
    155     protected final RegistrantList mSignalInfoRegistrants
    156     = new RegistrantList();
    157 
    158     protected final RegistrantList mCdmaOtaStatusChangeRegistrants
    159     = new RegistrantList();
    160 
    161     protected final RegistrantList mResendIncallMuteRegistrants
    162     = new RegistrantList();
    163 
    164     protected final RegistrantList mMmiInitiateRegistrants
    165     = new RegistrantList();
    166 
    167     protected final RegistrantList mMmiCompleteRegistrants
    168     = new RegistrantList();
    169 
    170     protected final RegistrantList mEcmTimerResetRegistrants
    171     = new RegistrantList();
    172 
    173     protected final RegistrantList mSubscriptionInfoReadyRegistrants
    174     = new RegistrantList();
    175 
    176     protected final RegistrantList mSuppServiceFailedRegistrants
    177     = new RegistrantList();
    178 
    179     protected final RegistrantList mServiceStateChangedRegistrants
    180     = new RegistrantList();
    181 
    182     protected final RegistrantList mPostDialCharacterRegistrants
    183     = new RegistrantList();
    184 
    185     protected final RegistrantList mTtyModeReceivedRegistrants
    186     = new RegistrantList();
    187 
    188     private CallManager() {
    189         mPhones = new ArrayList<Phone>();
    190         mRingingCalls = new ArrayList<Call>();
    191         mBackgroundCalls = new ArrayList<Call>();
    192         mForegroundCalls = new ArrayList<Call>();
    193         mDefaultPhone = null;
    194     }
    195 
    196     /**
    197      * get singleton instance of CallManager
    198      * @return CallManager
    199      */
    200     public static CallManager getInstance() {
    201         return INSTANCE;
    202     }
    203 
    204     /**
    205      * Get the corresponding PhoneBase obj
    206      *
    207      * @param phone a Phone object
    208      * @return the corresponding PhoneBase obj in Phone if Phone
    209      * is a PhoneProxy obj
    210      * or the Phone itself if Phone is not a PhoneProxy obj
    211      */
    212     private static Phone getPhoneBase(Phone phone) {
    213         if (phone instanceof PhoneProxy) {
    214             return phone.getForegroundCall().getPhone();
    215         }
    216         return phone;
    217     }
    218 
    219     /**
    220      * Check if two phones refer to the same PhoneBase obj
    221      *
    222      * Note: PhoneBase, not PhoneProxy, is to be used inside of CallManager
    223      *
    224      * Both PhoneBase and PhoneProxy implement Phone interface, so
    225      * they have same phone APIs, such as dial(). The real implementation, for
    226      * example in GSM,  is in GSMPhone as extend from PhoneBase, so that
    227      * foregroundCall.getPhone() returns GSMPhone obj. On the other hand,
    228      * PhoneFactory.getDefaultPhone() returns PhoneProxy obj, which has a class
    229      * member of GSMPhone.
    230      *
    231      * So for phone returned by PhoneFacotry, which is used by PhoneApp,
    232      *        phone.getForegroundCall().getPhone() != phone
    233      * but
    234      *        isSamePhone(phone, phone.getForegroundCall().getPhone()) == true
    235      *
    236      * @param p1 is the first Phone obj
    237      * @param p2 is the second Phone obj
    238      * @return true if p1 and p2 refer to the same phone
    239      */
    240     public static boolean isSamePhone(Phone p1, Phone p2) {
    241         return (getPhoneBase(p1) == getPhoneBase(p2));
    242     }
    243 
    244     /**
    245      * Returns all the registered phone objects.
    246      * @return all the registered phone objects.
    247      */
    248     public List<Phone> getAllPhones() {
    249         return Collections.unmodifiableList(mPhones);
    250     }
    251 
    252     /**
    253      * get Phone object corresponds to subId
    254      * @return Phone
    255      */
    256     private Phone getPhone(int subId) {
    257         Phone p = null;
    258         for (Phone phone : mPhones) {
    259             if (phone.getSubId() == subId && !(phone instanceof ImsPhone)) {
    260                 p = phone;
    261                 break;
    262             }
    263         }
    264         return p;
    265     }
    266 
    267     /**
    268      * Get current coarse-grained voice call state.
    269      * If the Call Manager has an active call and call waiting occurs,
    270      * then the phone state is RINGING not OFFHOOK
    271      *
    272      */
    273     public PhoneConstants.State getState() {
    274         PhoneConstants.State s = PhoneConstants.State.IDLE;
    275 
    276         for (Phone phone : mPhones) {
    277             if (phone.getState() == PhoneConstants.State.RINGING) {
    278                 s = PhoneConstants.State.RINGING;
    279             } else if (phone.getState() == PhoneConstants.State.OFFHOOK) {
    280                 if (s == PhoneConstants.State.IDLE) s = PhoneConstants.State.OFFHOOK;
    281             }
    282         }
    283         return s;
    284     }
    285 
    286     /**
    287      * Get current coarse-grained voice call state on a subId.
    288      * If the Call Manager has an active call and call waiting occurs,
    289      * then the phone state is RINGING not OFFHOOK
    290      *
    291      */
    292     public PhoneConstants.State getState(int subId) {
    293         PhoneConstants.State s = PhoneConstants.State.IDLE;
    294 
    295         for (Phone phone : mPhones) {
    296             if (phone.getSubId() == subId) {
    297                 if (phone.getState() == PhoneConstants.State.RINGING) {
    298                     s = PhoneConstants.State.RINGING;
    299                 } else if (phone.getState() == PhoneConstants.State.OFFHOOK) {
    300                     if (s == PhoneConstants.State.IDLE) s = PhoneConstants.State.OFFHOOK;
    301                 }
    302             }
    303         }
    304         return s;
    305     }
    306 
    307     /**
    308      * @return the service state of CallManager, which represents the
    309      * highest priority state of all the service states of phones
    310      *
    311      * The priority is defined as
    312      *
    313      * STATE_IN_SERIVCE > STATE_OUT_OF_SERIVCE > STATE_EMERGENCY > STATE_POWER_OFF
    314      *
    315      */
    316 
    317     public int getServiceState() {
    318         int resultState = ServiceState.STATE_OUT_OF_SERVICE;
    319 
    320         for (Phone phone : mPhones) {
    321             int serviceState = phone.getServiceState().getState();
    322             if (serviceState == ServiceState.STATE_IN_SERVICE) {
    323                 // IN_SERVICE has the highest priority
    324                 resultState = serviceState;
    325                 break;
    326             } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
    327                 // OUT_OF_SERVICE replaces EMERGENCY_ONLY and POWER_OFF
    328                 // Note: EMERGENCY_ONLY is not in use at this moment
    329                 if ( resultState == ServiceState.STATE_EMERGENCY_ONLY ||
    330                         resultState == ServiceState.STATE_POWER_OFF) {
    331                     resultState = serviceState;
    332                 }
    333             } else if (serviceState == ServiceState.STATE_EMERGENCY_ONLY) {
    334                 if (resultState == ServiceState.STATE_POWER_OFF) {
    335                     resultState = serviceState;
    336                 }
    337             }
    338         }
    339         return resultState;
    340     }
    341 
    342     /**
    343      * @return the Phone service state corresponds to subId
    344      */
    345     public int getServiceState(int subId) {
    346         int resultState = ServiceState.STATE_OUT_OF_SERVICE;
    347 
    348         for (Phone phone : mPhones) {
    349             if (phone.getSubId() == subId) {
    350                 int serviceState = phone.getServiceState().getState();
    351                 if (serviceState == ServiceState.STATE_IN_SERVICE) {
    352                     // IN_SERVICE has the highest priority
    353                     resultState = serviceState;
    354                     break;
    355                 } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
    356                     // OUT_OF_SERVICE replaces EMERGENCY_ONLY and POWER_OFF
    357                     // Note: EMERGENCY_ONLY is not in use at this moment
    358                     if ( resultState == ServiceState.STATE_EMERGENCY_ONLY ||
    359                             resultState == ServiceState.STATE_POWER_OFF) {
    360                         resultState = serviceState;
    361                     }
    362                 } else if (serviceState == ServiceState.STATE_EMERGENCY_ONLY) {
    363                     if (resultState == ServiceState.STATE_POWER_OFF) {
    364                         resultState = serviceState;
    365                     }
    366                 }
    367             }
    368         }
    369         return resultState;
    370     }
    371 
    372     /**
    373      * @return the phone associated with any call
    374      */
    375     public Phone getPhoneInCall() {
    376         Phone phone = null;
    377         if (!getFirstActiveRingingCall().isIdle()) {
    378             phone = getFirstActiveRingingCall().getPhone();
    379         } else if (!getActiveFgCall().isIdle()) {
    380             phone = getActiveFgCall().getPhone();
    381         } else {
    382             // If BG call is idle, we return default phone
    383             phone = getFirstActiveBgCall().getPhone();
    384         }
    385         return phone;
    386     }
    387 
    388     public Phone getPhoneInCall(int subId) {
    389         Phone phone = null;
    390         if (!getFirstActiveRingingCall(subId).isIdle()) {
    391             phone = getFirstActiveRingingCall(subId).getPhone();
    392         } else if (!getActiveFgCall(subId).isIdle()) {
    393             phone = getActiveFgCall(subId).getPhone();
    394         } else {
    395             // If BG call is idle, we return default phone
    396             phone = getFirstActiveBgCall(subId).getPhone();
    397         }
    398         return phone;
    399     }
    400 
    401     /**
    402      * Register phone to CallManager
    403      * @param phone to be registered
    404      * @return true if register successfully
    405      */
    406     public boolean registerPhone(Phone phone) {
    407         Phone basePhone = getPhoneBase(phone);
    408 
    409         if (basePhone != null && !mPhones.contains(basePhone)) {
    410 
    411             if (DBG) {
    412                 Rlog.d(LOG_TAG, "registerPhone(" +
    413                         phone.getPhoneName() + " " + phone + ")");
    414             }
    415 
    416             if (mPhones.isEmpty()) {
    417                 mDefaultPhone = basePhone;
    418             }
    419             mPhones.add(basePhone);
    420             mRingingCalls.add(basePhone.getRingingCall());
    421             mBackgroundCalls.add(basePhone.getBackgroundCall());
    422             mForegroundCalls.add(basePhone.getForegroundCall());
    423             registerForPhoneStates(basePhone);
    424             return true;
    425         }
    426         return false;
    427     }
    428 
    429     /**
    430      * unregister phone from CallManager
    431      * @param phone to be unregistered
    432      */
    433     public void unregisterPhone(Phone phone) {
    434         Phone basePhone = getPhoneBase(phone);
    435 
    436         if (basePhone != null && mPhones.contains(basePhone)) {
    437 
    438             if (DBG) {
    439                 Rlog.d(LOG_TAG, "unregisterPhone(" +
    440                         phone.getPhoneName() + " " + phone + ")");
    441             }
    442 
    443             Phone vPhone = basePhone.getImsPhone();
    444             if (vPhone != null) {
    445                unregisterPhone(vPhone);
    446             }
    447 
    448             mPhones.remove(basePhone);
    449             mRingingCalls.remove(basePhone.getRingingCall());
    450             mBackgroundCalls.remove(basePhone.getBackgroundCall());
    451             mForegroundCalls.remove(basePhone.getForegroundCall());
    452             unregisterForPhoneStates(basePhone);
    453             if (basePhone == mDefaultPhone) {
    454                 if (mPhones.isEmpty()) {
    455                     mDefaultPhone = null;
    456                 } else {
    457                     mDefaultPhone = mPhones.get(0);
    458                 }
    459             }
    460         }
    461     }
    462 
    463     /**
    464      * return the default phone or null if no phone available
    465      */
    466     public Phone getDefaultPhone() {
    467         return mDefaultPhone;
    468     }
    469 
    470     /**
    471      * @return the phone associated with the foreground call
    472      */
    473     public Phone getFgPhone() {
    474         return getActiveFgCall().getPhone();
    475     }
    476 
    477     /**
    478      * @return the phone associated with the foreground call
    479      * of a particular subId
    480      */
    481     public Phone getFgPhone(int subId) {
    482         return getActiveFgCall(subId).getPhone();
    483     }
    484 
    485     /**
    486      * @return the phone associated with the background call
    487      */
    488     public Phone getBgPhone() {
    489         return getFirstActiveBgCall().getPhone();
    490     }
    491 
    492     /**
    493      * @return the phone associated with the background call
    494      * of a particular subId
    495      */
    496     public Phone getBgPhone(int subId) {
    497         return getFirstActiveBgCall(subId).getPhone();
    498     }
    499 
    500     /**
    501      * @return the phone associated with the ringing call
    502      */
    503     public Phone getRingingPhone() {
    504         return getFirstActiveRingingCall().getPhone();
    505     }
    506 
    507     /**
    508      * @return the phone associated with the ringing call
    509      * of a particular subId
    510      */
    511     public Phone getRingingPhone(int subId) {
    512         return getFirstActiveRingingCall(subId).getPhone();
    513     }
    514 
    515     /* FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
    516     public void setAudioMode() {
    517         Context context = getContext();
    518         if (context == null) return;
    519         AudioManager audioManager = (AudioManager)
    520                 context.getSystemService(Context.AUDIO_SERVICE);
    521 
    522         if (!isServiceStateInService() && !mIsEccDialing) {
    523             if (audioManager.getMode() != AudioManager.MODE_NORMAL) {
    524                 if (VDBG) Rlog.d(LOG_TAG, "abandonAudioFocus");
    525                 // abandon audio focus after the mode has been set back to normal
    526                 audioManager.abandonAudioFocusForCall();
    527                 audioManager.setMode(AudioManager.MODE_NORMAL);
    528             }
    529             return;
    530         }
    531 
    532         // change the audio mode and request/abandon audio focus according to phone state,
    533         // but only on audio mode transitions
    534         switch (getState()) {
    535             case RINGING:
    536                 int curAudioMode = audioManager.getMode();
    537                 if (curAudioMode != AudioManager.MODE_RINGTONE) {
    538                     if (VDBG) Rlog.d(LOG_TAG, "requestAudioFocus on STREAM_RING");
    539                     audioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
    540                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
    541                     if(!mSpeedUpAudioForMtCall) {
    542                         audioManager.setMode(AudioManager.MODE_RINGTONE);
    543                     }
    544                 }
    545 
    546                 if (mSpeedUpAudioForMtCall && (curAudioMode != AudioManager.MODE_IN_CALL)) {
    547                     audioManager.setMode(AudioManager.MODE_IN_CALL);
    548                 }
    549                 break;
    550             case OFFHOOK:
    551                 Phone offhookPhone = getFgPhone();
    552                 if (getActiveFgCallState() == Call.State.IDLE) {
    553                     // There is no active Fg calls, the OFFHOOK state
    554                     // is set by the Bg call. So set the phone to bgPhone.
    555                     offhookPhone = getBgPhone();
    556                 }
    557 
    558                 int newAudioMode = AudioManager.MODE_IN_CALL;
    559                 if (offhookPhone instanceof SipPhone) {
    560                     Rlog.d(LOG_TAG, "setAudioMode Set audio mode for SIP call!");
    561                     // enable IN_COMMUNICATION audio mode instead for sipPhone
    562                     newAudioMode = AudioManager.MODE_IN_COMMUNICATION;
    563                 }
    564                 int currMode = audioManager.getMode();
    565                 if (currMode != newAudioMode || mSpeedUpAudioForMtCall) {
    566                     // request audio focus before setting the new mode
    567                     if (VDBG) Rlog.d(LOG_TAG, "requestAudioFocus on STREAM_VOICE_CALL");
    568                     audioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
    569                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
    570                     Rlog.d(LOG_TAG, "setAudioMode Setting audio mode from "
    571                             + currMode + " to " + newAudioMode);
    572                     audioManager.setMode(newAudioMode);
    573                 }
    574                 mSpeedUpAudioForMtCall = false;
    575                 break;
    576             case IDLE:
    577                 if (audioManager.getMode() != AudioManager.MODE_NORMAL) {
    578                     audioManager.setMode(AudioManager.MODE_NORMAL);
    579                     if (VDBG) Rlog.d(LOG_TAG, "abandonAudioFocus");
    580                     // abandon audio focus after the mode has been set back to normal
    581                     audioManager.abandonAudioFocusForCall();
    582                 }
    583                 mSpeedUpAudioForMtCall = false;
    584                 break;
    585         }
    586         Rlog.d(LOG_TAG, "setAudioMode state = " + getState());
    587     }
    588     */
    589 
    590     private Context getContext() {
    591         Phone defaultPhone = getDefaultPhone();
    592         return ((defaultPhone == null) ? null : defaultPhone.getContext());
    593     }
    594 
    595     private void registerForPhoneStates(Phone phone) {
    596         // We need to keep a mapping of handler to Phone for proper unregistration.
    597         // TODO: Clean up this solution as it is just a work around for each Phone instance
    598         // using the same Handler to register with the RIL. When time permits, we should consider
    599         // moving the handler (or the reference ot the handler) into the Phone object.
    600         // See b/17414427.
    601         CallManagerHandler handler = mHandlerMap.get(phone);
    602         if (handler != null) {
    603             Rlog.d(LOG_TAG, "This phone has already been registered.");
    604             return;
    605         }
    606 
    607         // New registration, create a new handler instance and register the phone.
    608         handler = new CallManagerHandler();
    609         mHandlerMap.put(phone, handler);
    610 
    611         // for common events supported by all phones
    612         phone.registerForPreciseCallStateChanged(handler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
    613         phone.registerForDisconnect(handler, EVENT_DISCONNECT, null);
    614         phone.registerForNewRingingConnection(handler, EVENT_NEW_RINGING_CONNECTION, null);
    615         phone.registerForUnknownConnection(handler, EVENT_UNKNOWN_CONNECTION, null);
    616         phone.registerForIncomingRing(handler, EVENT_INCOMING_RING, null);
    617         phone.registerForRingbackTone(handler, EVENT_RINGBACK_TONE, null);
    618         phone.registerForInCallVoicePrivacyOn(handler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);
    619         phone.registerForInCallVoicePrivacyOff(handler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);
    620         phone.registerForDisplayInfo(handler, EVENT_DISPLAY_INFO, null);
    621         phone.registerForSignalInfo(handler, EVENT_SIGNAL_INFO, null);
    622         phone.registerForResendIncallMute(handler, EVENT_RESEND_INCALL_MUTE, null);
    623         phone.registerForMmiInitiate(handler, EVENT_MMI_INITIATE, null);
    624         phone.registerForMmiComplete(handler, EVENT_MMI_COMPLETE, null);
    625         phone.registerForSuppServiceFailed(handler, EVENT_SUPP_SERVICE_FAILED, null);
    626         phone.registerForServiceStateChanged(handler, EVENT_SERVICE_STATE_CHANGED, null);
    627         // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
    628         //phone.registerForRadioOffOrNotAvailable(handler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
    629 
    630         // for events supported only by GSM, CDMA and IMS phone
    631         if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM ||
    632                 phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ||
    633                 phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
    634             phone.setOnPostDialCharacter(handler, EVENT_POST_DIAL_CHARACTER, null);
    635         }
    636 
    637         // for events supported only by CDMA phone
    638         if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ){
    639             phone.registerForCdmaOtaStatusChange(handler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
    640             phone.registerForSubscriptionInfoReady(handler, EVENT_SUBSCRIPTION_INFO_READY, null);
    641             phone.registerForCallWaiting(handler, EVENT_CALL_WAITING, null);
    642             phone.registerForEcmTimerReset(handler, EVENT_ECM_TIMER_RESET, null);
    643         }
    644 
    645         // for events supported only by IMS phone
    646         if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
    647             phone.registerForOnHoldTone(handler, EVENT_ONHOLD_TONE, null);
    648             phone.registerForSuppServiceFailed(handler, EVENT_SUPP_SERVICE_FAILED, null);
    649             phone.registerForTtyModeReceived(handler, EVENT_TTY_MODE_RECEIVED, null);
    650         }
    651     }
    652 
    653     private void unregisterForPhoneStates(Phone phone) {
    654         // Make sure that we clean up our map of handlers to Phones.
    655         CallManagerHandler handler = mHandlerMap.get(phone);
    656         if (handler != null) {
    657             Rlog.e(LOG_TAG, "Could not find Phone handler for unregistration");
    658             return;
    659         }
    660         mHandlerMap.remove(phone);
    661 
    662         //  for common events supported by all phones
    663         phone.unregisterForPreciseCallStateChanged(handler);
    664         phone.unregisterForDisconnect(handler);
    665         phone.unregisterForNewRingingConnection(handler);
    666         phone.unregisterForUnknownConnection(handler);
    667         phone.unregisterForIncomingRing(handler);
    668         phone.unregisterForRingbackTone(handler);
    669         phone.unregisterForInCallVoicePrivacyOn(handler);
    670         phone.unregisterForInCallVoicePrivacyOff(handler);
    671         phone.unregisterForDisplayInfo(handler);
    672         phone.unregisterForSignalInfo(handler);
    673         phone.unregisterForResendIncallMute(handler);
    674         phone.unregisterForMmiInitiate(handler);
    675         phone.unregisterForMmiComplete(handler);
    676         phone.unregisterForSuppServiceFailed(handler);
    677         phone.unregisterForServiceStateChanged(handler);
    678         phone.unregisterForTtyModeReceived(handler);
    679         // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
    680         //phone.unregisterForRadioOffOrNotAvailable(handler);
    681 
    682         // for events supported only by GSM, CDMA and IMS phone
    683         if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM ||
    684                 phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ||
    685                 phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
    686             phone.setOnPostDialCharacter(null, EVENT_POST_DIAL_CHARACTER, null);
    687         }
    688 
    689         // for events supported only by CDMA phone
    690         if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ){
    691             phone.unregisterForCdmaOtaStatusChange(handler);
    692             phone.unregisterForSubscriptionInfoReady(handler);
    693             phone.unregisterForCallWaiting(handler);
    694             phone.unregisterForEcmTimerReset(handler);
    695         }
    696 
    697         // for events supported only by IMS phone
    698         if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
    699             phone.unregisterForOnHoldTone(handler);
    700             phone.unregisterForSuppServiceFailed(handler);
    701         }
    702     }
    703 
    704     /**
    705      * Answers a ringing or waiting call.
    706      *
    707      * Active call, if any, go on hold.
    708      * If active call can't be held, i.e., a background call of the same channel exists,
    709      * the active call will be hang up.
    710      *
    711      * Answering occurs asynchronously, and final notification occurs via
    712      * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
    713      * java.lang.Object) registerForPreciseCallStateChanged()}.
    714      *
    715      * @exception CallStateException when call is not ringing or waiting
    716      */
    717     public void acceptCall(Call ringingCall) throws CallStateException {
    718         Phone ringingPhone = ringingCall.getPhone();
    719 
    720         if (VDBG) {
    721             Rlog.d(LOG_TAG, "acceptCall(" +ringingCall + " from " + ringingCall.getPhone() + ")");
    722             Rlog.d(LOG_TAG, toString());
    723         }
    724 
    725         if ( hasActiveFgCall() ) {
    726             Phone activePhone = getActiveFgCall().getPhone();
    727             boolean hasBgCall = ! (activePhone.getBackgroundCall().isIdle());
    728             boolean sameChannel = (activePhone == ringingPhone);
    729 
    730             if (VDBG) {
    731                 Rlog.d(LOG_TAG, "hasBgCall: "+ hasBgCall + "sameChannel:" + sameChannel);
    732             }
    733 
    734             if (sameChannel && hasBgCall) {
    735                 getActiveFgCall().hangup();
    736             } else if (!sameChannel && !hasBgCall) {
    737                 activePhone.switchHoldingAndActive();
    738             } else if (!sameChannel && hasBgCall) {
    739                 getActiveFgCall().hangup();
    740             }
    741         }
    742 
    743         // We only support the AUDIO_ONLY video state in this scenario.
    744         ringingPhone.acceptCall(VideoProfile.STATE_AUDIO_ONLY);
    745 
    746         if (VDBG) {
    747             Rlog.d(LOG_TAG, "End acceptCall(" +ringingCall + ")");
    748             Rlog.d(LOG_TAG, toString());
    749         }
    750     }
    751 
    752     /**
    753      * Reject (ignore) a ringing call. In GSM, this means UDUB
    754      * (User Determined User Busy). Reject occurs asynchronously,
    755      * and final notification occurs via
    756      * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
    757      * java.lang.Object) registerForPreciseCallStateChanged()}.
    758      *
    759      * @exception CallStateException when no call is ringing or waiting
    760      */
    761     public void rejectCall(Call ringingCall) throws CallStateException {
    762         if (VDBG) {
    763             Rlog.d(LOG_TAG, "rejectCall(" +ringingCall + ")");
    764             Rlog.d(LOG_TAG, toString());
    765         }
    766 
    767         Phone ringingPhone = ringingCall.getPhone();
    768 
    769         ringingPhone.rejectCall();
    770 
    771         if (VDBG) {
    772             Rlog.d(LOG_TAG, "End rejectCall(" +ringingCall + ")");
    773             Rlog.d(LOG_TAG, toString());
    774         }
    775     }
    776 
    777     /**
    778      * Places active call on hold, and makes held call active.
    779      * Switch occurs asynchronously and may fail.
    780      *
    781      * There are 4 scenarios
    782      * 1. only active call but no held call, aka, hold
    783      * 2. no active call but only held call, aka, unhold
    784      * 3. both active and held calls from same phone, aka, swap
    785      * 4. active and held calls from different phones, aka, phone swap
    786      *
    787      * Final notification occurs via
    788      * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
    789      * java.lang.Object) registerForPreciseCallStateChanged()}.
    790      *
    791      * @exception CallStateException if active call is ringing, waiting, or
    792      * dialing/alerting, or heldCall can't be active.
    793      * In these cases, this operation may not be performed.
    794      */
    795     public void switchHoldingAndActive(Call heldCall) throws CallStateException {
    796         Phone activePhone = null;
    797         Phone heldPhone = null;
    798 
    799         if (VDBG) {
    800             Rlog.d(LOG_TAG, "switchHoldingAndActive(" +heldCall + ")");
    801             Rlog.d(LOG_TAG, toString());
    802         }
    803 
    804         if (hasActiveFgCall()) {
    805             activePhone = getActiveFgCall().getPhone();
    806         }
    807 
    808         if (heldCall != null) {
    809             heldPhone = heldCall.getPhone();
    810         }
    811 
    812         if (activePhone != null) {
    813             activePhone.switchHoldingAndActive();
    814         }
    815 
    816         if (heldPhone != null && heldPhone != activePhone) {
    817             heldPhone.switchHoldingAndActive();
    818         }
    819 
    820         if (VDBG) {
    821             Rlog.d(LOG_TAG, "End switchHoldingAndActive(" +heldCall + ")");
    822             Rlog.d(LOG_TAG, toString());
    823         }
    824     }
    825 
    826     /**
    827      * Hangup foreground call and resume the specific background call
    828      *
    829      * Note: this is noop if there is no foreground call or the heldCall is null
    830      *
    831      * @param heldCall to become foreground
    832      * @throws CallStateException
    833      */
    834     public void hangupForegroundResumeBackground(Call heldCall) throws CallStateException {
    835         Phone foregroundPhone = null;
    836         Phone backgroundPhone = null;
    837 
    838         if (VDBG) {
    839             Rlog.d(LOG_TAG, "hangupForegroundResumeBackground(" +heldCall + ")");
    840             Rlog.d(LOG_TAG, toString());
    841         }
    842 
    843         if (hasActiveFgCall()) {
    844             foregroundPhone = getFgPhone();
    845             if (heldCall != null) {
    846                 backgroundPhone = heldCall.getPhone();
    847                 if (foregroundPhone == backgroundPhone) {
    848                     getActiveFgCall().hangup();
    849                 } else {
    850                 // the call to be hangup and resumed belongs to different phones
    851                     getActiveFgCall().hangup();
    852                     switchHoldingAndActive(heldCall);
    853                 }
    854             }
    855         }
    856 
    857         if (VDBG) {
    858             Rlog.d(LOG_TAG, "End hangupForegroundResumeBackground(" +heldCall + ")");
    859             Rlog.d(LOG_TAG, toString());
    860         }
    861     }
    862 
    863     /**
    864      * Whether or not the phone can conference in the current phone
    865      * state--that is, one call holding and one call active.
    866      * @return true if the phone can conference; false otherwise.
    867      */
    868     public boolean canConference(Call heldCall) {
    869         Phone activePhone = null;
    870         Phone heldPhone = null;
    871 
    872         if (hasActiveFgCall()) {
    873             activePhone = getActiveFgCall().getPhone();
    874         }
    875 
    876         if (heldCall != null) {
    877             heldPhone = heldCall.getPhone();
    878         }
    879 
    880         return heldPhone.getClass().equals(activePhone.getClass());
    881     }
    882 
    883     /**
    884      * Whether or not the phone can conference in the current phone
    885      * state--that is, one call holding and one call active.
    886      * This method consider the phone object which is specific
    887      * to the provided subId.
    888      * @return true if the phone can conference; false otherwise.
    889      */
    890     public boolean canConference(Call heldCall, int subId) {
    891         Phone activePhone = null;
    892         Phone heldPhone = null;
    893 
    894         if (hasActiveFgCall(subId)) {
    895             activePhone = getActiveFgCall(subId).getPhone();
    896         }
    897 
    898         if (heldCall != null) {
    899             heldPhone = heldCall.getPhone();
    900         }
    901 
    902         return heldPhone.getClass().equals(activePhone.getClass());
    903     }
    904 
    905     /**
    906      * Conferences holding and active. Conference occurs asynchronously
    907      * and may fail. Final notification occurs via
    908      * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
    909      * java.lang.Object) registerForPreciseCallStateChanged()}.
    910      *
    911      * @exception CallStateException if canConference() would return false.
    912      * In these cases, this operation may not be performed.
    913      */
    914     public void conference(Call heldCall) throws CallStateException {
    915         int subId  = heldCall.getPhone().getSubId();
    916 
    917         if (VDBG) {
    918             Rlog.d(LOG_TAG, "conference(" +heldCall + ")");
    919             Rlog.d(LOG_TAG, toString());
    920         }
    921 
    922         Phone fgPhone = getFgPhone(subId);
    923         if (fgPhone != null) {
    924             if (fgPhone instanceof SipPhone) {
    925                 ((SipPhone) fgPhone).conference(heldCall);
    926             } else if (canConference(heldCall)) {
    927                 fgPhone.conference();
    928             } else {
    929                 throw(new CallStateException("Can't conference foreground and selected background call"));
    930             }
    931         } else {
    932             Rlog.d(LOG_TAG, "conference: fgPhone=null");
    933         }
    934 
    935         if (VDBG) {
    936             Rlog.d(LOG_TAG, "End conference(" +heldCall + ")");
    937             Rlog.d(LOG_TAG, toString());
    938         }
    939 
    940     }
    941 
    942     /**
    943      * Initiate a new voice connection. This happens asynchronously, so you
    944      * cannot assume the audio path is connected (or a call index has been
    945      * assigned) until PhoneStateChanged notification has occurred.
    946      *
    947      * @exception CallStateException if a new outgoing call is not currently
    948      * possible because no more call slots exist or a call exists that is
    949      * dialing, alerting, ringing, or waiting.  Other errors are
    950      * handled asynchronously.
    951      */
    952     public Connection dial(Phone phone, String dialString, int videoState)
    953             throws CallStateException {
    954         Phone basePhone = getPhoneBase(phone);
    955         int subId = phone.getSubId();
    956         Connection result;
    957 
    958         if (VDBG) {
    959             Rlog.d(LOG_TAG, " dial(" + basePhone + ", "+ dialString + ")" +
    960                     " subId = " + subId);
    961             Rlog.d(LOG_TAG, toString());
    962         }
    963 
    964         if (!canDial(phone)) {
    965             /*
    966              * canDial function only checks whether the phone can make a new call.
    967              * InCall MMI commmands are basically supplementary services
    968              * within a call eg: call hold, call deflection, explicit call transfer etc.
    969              */
    970             String newDialString = PhoneNumberUtils.stripSeparators(dialString);
    971             if (basePhone.handleInCallMmiCommands(newDialString)) {
    972                 return null;
    973             } else {
    974                 throw new CallStateException("cannot dial in current state");
    975             }
    976         }
    977 
    978         if ( hasActiveFgCall(subId) ) {
    979             Phone activePhone = getActiveFgCall(subId).getPhone();
    980             boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());
    981 
    982             if (DBG) {
    983                 Rlog.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == basePhone));
    984             }
    985 
    986             // Manipulation between IMS phone and its owner
    987             // will be treated in GSM/CDMA phone.
    988             Phone vPhone = basePhone.getImsPhone();
    989             if (activePhone != basePhone
    990                     && (vPhone == null || vPhone != activePhone)) {
    991                 if (hasBgCall) {
    992                     Rlog.d(LOG_TAG, "Hangup");
    993                     getActiveFgCall(subId).hangup();
    994                 } else {
    995                     Rlog.d(LOG_TAG, "Switch");
    996                     activePhone.switchHoldingAndActive();
    997                 }
    998             }
    999         }
   1000 
   1001         // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
   1002         //mIsEccDialing = PhoneNumberUtils.isEmergencyNumber(dialString);
   1003 
   1004         result = basePhone.dial(dialString, videoState);
   1005 
   1006         if (VDBG) {
   1007             Rlog.d(LOG_TAG, "End dial(" + basePhone + ", "+ dialString + ")");
   1008             Rlog.d(LOG_TAG, toString());
   1009         }
   1010 
   1011         return result;
   1012     }
   1013 
   1014     /**
   1015      * Initiate a new voice connection. This happens asynchronously, so you
   1016      * cannot assume the audio path is connected (or a call index has been
   1017      * assigned) until PhoneStateChanged notification has occurred.
   1018      *
   1019      * @exception CallStateException if a new outgoing call is not currently
   1020      * possible because no more call slots exist or a call exists that is
   1021      * dialing, alerting, ringing, or waiting.  Other errors are
   1022      * handled asynchronously.
   1023      */
   1024     public Connection dial(Phone phone, String dialString, UUSInfo uusInfo, int videoState)
   1025             throws CallStateException {
   1026         return phone.dial(dialString, uusInfo, videoState, null);
   1027     }
   1028 
   1029     /**
   1030      * clear disconnect connection for each phone
   1031      */
   1032     public void clearDisconnected() {
   1033         for(Phone phone : mPhones) {
   1034             phone.clearDisconnected();
   1035         }
   1036     }
   1037 
   1038     /**
   1039      * clear disconnect connection for a phone specific
   1040      * to the provided subId
   1041      */
   1042     public void clearDisconnected(int subId) {
   1043         for(Phone phone : mPhones) {
   1044             if (phone.getSubId() == subId) {
   1045                 phone.clearDisconnected();
   1046             }
   1047         }
   1048     }
   1049 
   1050     /**
   1051      * Phone can make a call only if ALL of the following are true:
   1052      *        - Phone is not powered off
   1053      *        - There's no incoming or waiting call
   1054      *        - The foreground call is ACTIVE or IDLE or DISCONNECTED.
   1055      *          (We mainly need to make sure it *isn't* DIALING or ALERTING.)
   1056      * @param phone
   1057      * @return true if the phone can make a new call
   1058      */
   1059     private boolean canDial(Phone phone) {
   1060         int serviceState = phone.getServiceState().getState();
   1061         int subId = phone.getSubId();
   1062         boolean hasRingingCall = hasActiveRingingCall();
   1063         Call.State fgCallState = getActiveFgCallState(subId);
   1064 
   1065         boolean result = (serviceState != ServiceState.STATE_POWER_OFF
   1066                 && !hasRingingCall
   1067                 && ((fgCallState == Call.State.ACTIVE)
   1068                     || (fgCallState == Call.State.IDLE)
   1069                     || (fgCallState == Call.State.DISCONNECTED)
   1070                     /*As per 3GPP TS 51.010-1 section 31.13.1.4
   1071                     call should be alowed when the foreground
   1072                     call is in ALERTING state*/
   1073                     || (fgCallState == Call.State.ALERTING)));
   1074 
   1075         if (result == false) {
   1076             Rlog.d(LOG_TAG, "canDial serviceState=" + serviceState
   1077                             + " hasRingingCall=" + hasRingingCall
   1078                             + " fgCallState=" + fgCallState);
   1079         }
   1080         return result;
   1081     }
   1082 
   1083     /**
   1084      * Whether or not the phone can do explicit call transfer in the current
   1085      * phone state--that is, one call holding and one call active.
   1086      * @return true if the phone can do explicit call transfer; false otherwise.
   1087      */
   1088     public boolean canTransfer(Call heldCall) {
   1089         Phone activePhone = null;
   1090         Phone heldPhone = null;
   1091 
   1092         if (hasActiveFgCall()) {
   1093             activePhone = getActiveFgCall().getPhone();
   1094         }
   1095 
   1096         if (heldCall != null) {
   1097             heldPhone = heldCall.getPhone();
   1098         }
   1099 
   1100         return (heldPhone == activePhone && activePhone.canTransfer());
   1101     }
   1102 
   1103     /**
   1104      * Whether or not the phone specific to subId can do explicit call transfer
   1105      * in the current phone state--that is, one call holding and one call active.
   1106      * @return true if the phone can do explicit call transfer; false otherwise.
   1107      */
   1108     public boolean canTransfer(Call heldCall, int subId) {
   1109         Phone activePhone = null;
   1110         Phone heldPhone = null;
   1111 
   1112         if (hasActiveFgCall(subId)) {
   1113             activePhone = getActiveFgCall(subId).getPhone();
   1114         }
   1115 
   1116         if (heldCall != null) {
   1117             heldPhone = heldCall.getPhone();
   1118         }
   1119 
   1120         return (heldPhone == activePhone && activePhone.canTransfer());
   1121     }
   1122 
   1123     /**
   1124      * Connects the held call and active call
   1125      * Disconnects the subscriber from both calls
   1126      *
   1127      * Explicit Call Transfer occurs asynchronously
   1128      * and may fail. Final notification occurs via
   1129      * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
   1130      * java.lang.Object) registerForPreciseCallStateChanged()}.
   1131      *
   1132      * @exception CallStateException if canTransfer() would return false.
   1133      * In these cases, this operation may not be performed.
   1134      */
   1135     public void explicitCallTransfer(Call heldCall) throws CallStateException {
   1136         if (VDBG) {
   1137             Rlog.d(LOG_TAG, " explicitCallTransfer(" + heldCall + ")");
   1138             Rlog.d(LOG_TAG, toString());
   1139         }
   1140 
   1141         if (canTransfer(heldCall)) {
   1142             heldCall.getPhone().explicitCallTransfer();
   1143         }
   1144 
   1145         if (VDBG) {
   1146             Rlog.d(LOG_TAG, "End explicitCallTransfer(" + heldCall + ")");
   1147             Rlog.d(LOG_TAG, toString());
   1148         }
   1149 
   1150     }
   1151 
   1152     /**
   1153      * Returns a list of MMI codes that are pending for a phone. (They have initiated
   1154      * but have not yet completed).
   1155      * Presently there is only ever one.
   1156      *
   1157      * Use <code>registerForMmiInitiate</code>
   1158      * and <code>registerForMmiComplete</code> for change notification.
   1159      * @return null if phone doesn't have or support mmi code
   1160      */
   1161     public List<? extends MmiCode> getPendingMmiCodes(Phone phone) {
   1162         Rlog.e(LOG_TAG, "getPendingMmiCodes not implemented");
   1163         return null;
   1164     }
   1165 
   1166     /**
   1167      * Sends user response to a USSD REQUEST message.  An MmiCode instance
   1168      * representing this response is sent to handlers registered with
   1169      * registerForMmiInitiate.
   1170      *
   1171      * @param ussdMessge    Message to send in the response.
   1172      * @return false if phone doesn't support ussd service
   1173      */
   1174     public boolean sendUssdResponse(Phone phone, String ussdMessge) {
   1175         Rlog.e(LOG_TAG, "sendUssdResponse not implemented");
   1176         return false;
   1177     }
   1178 
   1179     /**
   1180      * Mutes or unmutes the microphone for the active call. The microphone
   1181      * is automatically unmuted if a call is answered, dialed, or resumed
   1182      * from a holding state.
   1183      *
   1184      * @param muted true to mute the microphone,
   1185      * false to activate the microphone.
   1186      */
   1187 
   1188     public void setMute(boolean muted) {
   1189         if (VDBG) {
   1190             Rlog.d(LOG_TAG, " setMute(" + muted + ")");
   1191             Rlog.d(LOG_TAG, toString());
   1192         }
   1193 
   1194         if (hasActiveFgCall()) {
   1195             getActiveFgCall().getPhone().setMute(muted);
   1196         }
   1197 
   1198         if (VDBG) {
   1199             Rlog.d(LOG_TAG, "End setMute(" + muted + ")");
   1200             Rlog.d(LOG_TAG, toString());
   1201         }
   1202     }
   1203 
   1204     /**
   1205      * Gets current mute status. Use
   1206      * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
   1207      * java.lang.Object) registerForPreciseCallStateChanged()}
   1208      * as a change notifcation, although presently phone state changed is not
   1209      * fired when setMute() is called.
   1210      *
   1211      * @return true is muting, false is unmuting
   1212      */
   1213     public boolean getMute() {
   1214         if (hasActiveFgCall()) {
   1215             return getActiveFgCall().getPhone().getMute();
   1216         } else if (hasActiveBgCall()) {
   1217             return getFirstActiveBgCall().getPhone().getMute();
   1218         }
   1219         return false;
   1220     }
   1221 
   1222     /**
   1223      * Enables or disables echo suppression.
   1224      */
   1225     public void setEchoSuppressionEnabled() {
   1226         if (VDBG) {
   1227             Rlog.d(LOG_TAG, " setEchoSuppression()");
   1228             Rlog.d(LOG_TAG, toString());
   1229         }
   1230 
   1231         if (hasActiveFgCall()) {
   1232             getActiveFgCall().getPhone().setEchoSuppressionEnabled();
   1233         }
   1234 
   1235         if (VDBG) {
   1236             Rlog.d(LOG_TAG, "End setEchoSuppression()");
   1237             Rlog.d(LOG_TAG, toString());
   1238         }
   1239     }
   1240 
   1241     /**
   1242      * Play a DTMF tone on the active call.
   1243      *
   1244      * @param c should be one of 0-9, '*' or '#'. Other values will be
   1245      * silently ignored.
   1246      * @return false if no active call or the active call doesn't support
   1247      *         dtmf tone
   1248      */
   1249     public boolean sendDtmf(char c) {
   1250         boolean result = false;
   1251 
   1252         if (VDBG) {
   1253             Rlog.d(LOG_TAG, " sendDtmf(" + c + ")");
   1254             Rlog.d(LOG_TAG, toString());
   1255         }
   1256 
   1257         if (hasActiveFgCall()) {
   1258             getActiveFgCall().getPhone().sendDtmf(c);
   1259             result = true;
   1260         }
   1261 
   1262         if (VDBG) {
   1263             Rlog.d(LOG_TAG, "End sendDtmf(" + c + ")");
   1264             Rlog.d(LOG_TAG, toString());
   1265         }
   1266         return result;
   1267     }
   1268 
   1269     /**
   1270      * Start to paly a DTMF tone on the active call.
   1271      * or there is a playing DTMF tone.
   1272      * @param c should be one of 0-9, '*' or '#'. Other values will be
   1273      * silently ignored.
   1274      *
   1275      * @return false if no active call or the active call doesn't support
   1276      *         dtmf tone
   1277      */
   1278     public boolean startDtmf(char c) {
   1279         boolean result = false;
   1280 
   1281         if (VDBG) {
   1282             Rlog.d(LOG_TAG, " startDtmf(" + c + ")");
   1283             Rlog.d(LOG_TAG, toString());
   1284         }
   1285 
   1286         if (hasActiveFgCall()) {
   1287             getActiveFgCall().getPhone().startDtmf(c);
   1288             result = true;
   1289         }
   1290 
   1291         if (VDBG) {
   1292             Rlog.d(LOG_TAG, "End startDtmf(" + c + ")");
   1293             Rlog.d(LOG_TAG, toString());
   1294         }
   1295 
   1296         return result;
   1297     }
   1298 
   1299     /**
   1300      * Stop the playing DTMF tone. Ignored if there is no playing DTMF
   1301      * tone or no active call.
   1302      */
   1303     public void stopDtmf() {
   1304         if (VDBG) {
   1305             Rlog.d(LOG_TAG, " stopDtmf()" );
   1306             Rlog.d(LOG_TAG, toString());
   1307         }
   1308 
   1309         if (hasActiveFgCall()) getFgPhone().stopDtmf();
   1310 
   1311         if (VDBG) {
   1312             Rlog.d(LOG_TAG, "End stopDtmf()");
   1313             Rlog.d(LOG_TAG, toString());
   1314         }
   1315     }
   1316 
   1317     /**
   1318      * send burst DTMF tone, it can send the string as single character or multiple character
   1319      * ignore if there is no active call or not valid digits string.
   1320      * Valid digit means only includes characters ISO-LATIN characters 0-9, *, #
   1321      * The difference between sendDtmf and sendBurstDtmf is sendDtmf only sends one character,
   1322      * this api can send single character and multiple character, also, this api has response
   1323      * back to caller.
   1324      *
   1325      * @param dtmfString is string representing the dialing digit(s) in the active call
   1326      * @param on the DTMF ON length in milliseconds, or 0 for default
   1327      * @param off the DTMF OFF length in milliseconds, or 0 for default
   1328      * @param onComplete is the callback message when the action is processed by BP
   1329      *
   1330      */
   1331     public boolean sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
   1332         if (hasActiveFgCall()) {
   1333             getActiveFgCall().getPhone().sendBurstDtmf(dtmfString, on, off, onComplete);
   1334             return true;
   1335         }
   1336         return false;
   1337     }
   1338 
   1339     /**
   1340      * Notifies when a voice connection has disconnected, either due to local
   1341      * or remote hangup or error.
   1342      *
   1343      *  Messages received from this will have the following members:<p>
   1344      *  <ul><li>Message.obj will be an AsyncResult</li>
   1345      *  <li>AsyncResult.userObj = obj</li>
   1346      *  <li>AsyncResult.result = a Connection object that is
   1347      *  no longer connected.</li></ul>
   1348      */
   1349     public void registerForDisconnect(Handler h, int what, Object obj) {
   1350         mDisconnectRegistrants.addUnique(h, what, obj);
   1351     }
   1352 
   1353     /**
   1354      * Unregisters for voice disconnection notification.
   1355      * Extraneous calls are tolerated silently
   1356      */
   1357     public void unregisterForDisconnect(Handler h){
   1358         mDisconnectRegistrants.remove(h);
   1359     }
   1360 
   1361     /**
   1362      * Register for getting notifications for change in the Call State {@link Call.State}
   1363      * This is called PreciseCallState because the call state is more precise than what
   1364      * can be obtained using the {@link PhoneStateListener}
   1365      *
   1366      * Resulting events will have an AsyncResult in <code>Message.obj</code>.
   1367      * AsyncResult.userData will be set to the obj argument here.
   1368      * The <em>h</em> parameter is held only by a weak reference.
   1369      */
   1370     public void registerForPreciseCallStateChanged(Handler h, int what, Object obj){
   1371         mPreciseCallStateRegistrants.addUnique(h, what, obj);
   1372     }
   1373 
   1374     /**
   1375      * Unregisters for voice call state change notifications.
   1376      * Extraneous calls are tolerated silently.
   1377      */
   1378     public void unregisterForPreciseCallStateChanged(Handler h){
   1379         mPreciseCallStateRegistrants.remove(h);
   1380     }
   1381 
   1382     /**
   1383      * Notifies when a previously untracked non-ringing/waiting connection has appeared.
   1384      * This is likely due to some other entity (eg, SIM card application) initiating a call.
   1385      */
   1386     public void registerForUnknownConnection(Handler h, int what, Object obj){
   1387         mUnknownConnectionRegistrants.addUnique(h, what, obj);
   1388     }
   1389 
   1390     /**
   1391      * Unregisters for unknown connection notifications.
   1392      */
   1393     public void unregisterForUnknownConnection(Handler h){
   1394         mUnknownConnectionRegistrants.remove(h);
   1395     }
   1396 
   1397 
   1398     /**
   1399      * Notifies when a new ringing or waiting connection has appeared.<p>
   1400      *
   1401      *  Messages received from this:
   1402      *  Message.obj will be an AsyncResult
   1403      *  AsyncResult.userObj = obj
   1404      *  AsyncResult.result = a Connection. <p>
   1405      *  Please check Connection.isRinging() to make sure the Connection
   1406      *  has not dropped since this message was posted.
   1407      *  If Connection.isRinging() is true, then
   1408      *   Connection.getCall() == Phone.getRingingCall()
   1409      */
   1410     public void registerForNewRingingConnection(Handler h, int what, Object obj){
   1411         mNewRingingConnectionRegistrants.addUnique(h, what, obj);
   1412     }
   1413 
   1414     /**
   1415      * Unregisters for new ringing connection notification.
   1416      * Extraneous calls are tolerated silently
   1417      */
   1418 
   1419     public void unregisterForNewRingingConnection(Handler h){
   1420         mNewRingingConnectionRegistrants.remove(h);
   1421     }
   1422 
   1423     /**
   1424      * Notifies when an incoming call rings.<p>
   1425      *
   1426      *  Messages received from this:
   1427      *  Message.obj will be an AsyncResult
   1428      *  AsyncResult.userObj = obj
   1429      *  AsyncResult.result = a Connection. <p>
   1430      */
   1431     public void registerForIncomingRing(Handler h, int what, Object obj){
   1432         mIncomingRingRegistrants.addUnique(h, what, obj);
   1433     }
   1434 
   1435     /**
   1436      * Unregisters for ring notification.
   1437      * Extraneous calls are tolerated silently
   1438      */
   1439 
   1440     public void unregisterForIncomingRing(Handler h){
   1441         mIncomingRingRegistrants.remove(h);
   1442     }
   1443 
   1444     /**
   1445      * Notifies when out-band ringback tone is needed.<p>
   1446      *
   1447      *  Messages received from this:
   1448      *  Message.obj will be an AsyncResult
   1449      *  AsyncResult.userObj = obj
   1450      *  AsyncResult.result = boolean, true to start play ringback tone
   1451      *                       and false to stop. <p>
   1452      */
   1453     public void registerForRingbackTone(Handler h, int what, Object obj){
   1454         mRingbackToneRegistrants.addUnique(h, what, obj);
   1455     }
   1456 
   1457     /**
   1458      * Unregisters for ringback tone notification.
   1459      */
   1460 
   1461     public void unregisterForRingbackTone(Handler h){
   1462         mRingbackToneRegistrants.remove(h);
   1463     }
   1464 
   1465     /**
   1466      * Notifies when out-band on-hold tone is needed.<p>
   1467      *
   1468      *  Messages received from this:
   1469      *  Message.obj will be an AsyncResult
   1470      *  AsyncResult.userObj = obj
   1471      *  AsyncResult.result = boolean, true to start play on-hold tone
   1472      *                       and false to stop. <p>
   1473      */
   1474     public void registerForOnHoldTone(Handler h, int what, Object obj){
   1475         mOnHoldToneRegistrants.addUnique(h, what, obj);
   1476     }
   1477 
   1478     /**
   1479      * Unregisters for on-hold tone notification.
   1480      */
   1481 
   1482     public void unregisterForOnHoldTone(Handler h){
   1483         mOnHoldToneRegistrants.remove(h);
   1484     }
   1485 
   1486     /**
   1487      * Registers the handler to reset the uplink mute state to get
   1488      * uplink audio.
   1489      */
   1490     public void registerForResendIncallMute(Handler h, int what, Object obj){
   1491         mResendIncallMuteRegistrants.addUnique(h, what, obj);
   1492     }
   1493 
   1494     /**
   1495      * Unregisters for resend incall mute notifications.
   1496      */
   1497     public void unregisterForResendIncallMute(Handler h){
   1498         mResendIncallMuteRegistrants.remove(h);
   1499     }
   1500 
   1501     /**
   1502      * Register for notifications of initiation of a new MMI code request.
   1503      * MMI codes for GSM are discussed in 3GPP TS 22.030.<p>
   1504      *
   1505      * Example: If Phone.dial is called with "*#31#", then the app will
   1506      * be notified here.<p>
   1507      *
   1508      * The returned <code>Message.obj</code> will contain an AsyncResult.
   1509      *
   1510      * <code>obj.result</code> will be an "MmiCode" object.
   1511      */
   1512     public void registerForMmiInitiate(Handler h, int what, Object obj){
   1513         mMmiInitiateRegistrants.addUnique(h, what, obj);
   1514     }
   1515 
   1516     /**
   1517      * Unregisters for new MMI initiate notification.
   1518      * Extraneous calls are tolerated silently
   1519      */
   1520     public void unregisterForMmiInitiate(Handler h){
   1521         mMmiInitiateRegistrants.remove(h);
   1522     }
   1523 
   1524     /**
   1525      * Register for notifications that an MMI request has completed
   1526      * its network activity and is in its final state. This may mean a state
   1527      * of COMPLETE, FAILED, or CANCELLED.
   1528      *
   1529      * <code>Message.obj</code> will contain an AsyncResult.
   1530      * <code>obj.result</code> will be an "MmiCode" object
   1531      */
   1532     public void registerForMmiComplete(Handler h, int what, Object obj){
   1533         mMmiCompleteRegistrants.addUnique(h, what, obj);
   1534     }
   1535 
   1536     /**
   1537      * Unregisters for MMI complete notification.
   1538      * Extraneous calls are tolerated silently
   1539      */
   1540     public void unregisterForMmiComplete(Handler h){
   1541         mMmiCompleteRegistrants.remove(h);
   1542     }
   1543 
   1544     /**
   1545      * Registration point for Ecm timer reset
   1546      * @param h handler to notify
   1547      * @param what user-defined message code
   1548      * @param obj placed in Message.obj
   1549      */
   1550     public void registerForEcmTimerReset(Handler h, int what, Object obj){
   1551         mEcmTimerResetRegistrants.addUnique(h, what, obj);
   1552     }
   1553 
   1554     /**
   1555      * Unregister for notification for Ecm timer reset
   1556      * @param h Handler to be removed from the registrant list.
   1557      */
   1558     public void unregisterForEcmTimerReset(Handler h){
   1559         mEcmTimerResetRegistrants.remove(h);
   1560     }
   1561 
   1562     /**
   1563      * Register for ServiceState changed.
   1564      * Message.obj will contain an AsyncResult.
   1565      * AsyncResult.result will be a ServiceState instance
   1566      */
   1567     public void registerForServiceStateChanged(Handler h, int what, Object obj){
   1568         mServiceStateChangedRegistrants.addUnique(h, what, obj);
   1569     }
   1570 
   1571     /**
   1572      * Unregisters for ServiceStateChange notification.
   1573      * Extraneous calls are tolerated silently
   1574      */
   1575     public void unregisterForServiceStateChanged(Handler h){
   1576         mServiceStateChangedRegistrants.remove(h);
   1577     }
   1578 
   1579     /**
   1580      * Register for notifications when a supplementary service attempt fails.
   1581      * Message.obj will contain an AsyncResult.
   1582      *
   1583      * @param h Handler that receives the notification message.
   1584      * @param what User-defined message code.
   1585      * @param obj User object.
   1586      */
   1587     public void registerForSuppServiceFailed(Handler h, int what, Object obj){
   1588         mSuppServiceFailedRegistrants.addUnique(h, what, obj);
   1589     }
   1590 
   1591     /**
   1592      * Unregister for notifications when a supplementary service attempt fails.
   1593      * Extraneous calls are tolerated silently
   1594      *
   1595      * @param h Handler to be removed from the registrant list.
   1596      */
   1597     public void unregisterForSuppServiceFailed(Handler h){
   1598         mSuppServiceFailedRegistrants.remove(h);
   1599     }
   1600 
   1601     /**
   1602      * Register for notifications when a sInCall VoicePrivacy is enabled
   1603      *
   1604      * @param h Handler that receives the notification message.
   1605      * @param what User-defined message code.
   1606      * @param obj User object.
   1607      */
   1608     public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
   1609         mInCallVoicePrivacyOnRegistrants.addUnique(h, what, obj);
   1610     }
   1611 
   1612     /**
   1613      * Unregister for notifications when a sInCall VoicePrivacy is enabled
   1614      *
   1615      * @param h Handler to be removed from the registrant list.
   1616      */
   1617     public void unregisterForInCallVoicePrivacyOn(Handler h){
   1618         mInCallVoicePrivacyOnRegistrants.remove(h);
   1619     }
   1620 
   1621     /**
   1622      * Register for notifications when a sInCall VoicePrivacy is disabled
   1623      *
   1624      * @param h Handler that receives the notification message.
   1625      * @param what User-defined message code.
   1626      * @param obj User object.
   1627      */
   1628     public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
   1629         mInCallVoicePrivacyOffRegistrants.addUnique(h, what, obj);
   1630     }
   1631 
   1632     /**
   1633      * Unregister for notifications when a sInCall VoicePrivacy is disabled
   1634      *
   1635      * @param h Handler to be removed from the registrant list.
   1636      */
   1637     public void unregisterForInCallVoicePrivacyOff(Handler h){
   1638         mInCallVoicePrivacyOffRegistrants.remove(h);
   1639     }
   1640 
   1641     /**
   1642      * Register for notifications when CDMA call waiting comes
   1643      *
   1644      * @param h Handler that receives the notification message.
   1645      * @param what User-defined message code.
   1646      * @param obj User object.
   1647      */
   1648     public void registerForCallWaiting(Handler h, int what, Object obj){
   1649         mCallWaitingRegistrants.addUnique(h, what, obj);
   1650     }
   1651 
   1652     /**
   1653      * Unregister for notifications when CDMA Call waiting comes
   1654      * @param h Handler to be removed from the registrant list.
   1655      */
   1656     public void unregisterForCallWaiting(Handler h){
   1657         mCallWaitingRegistrants.remove(h);
   1658     }
   1659 
   1660 
   1661     /**
   1662      * Register for signal information notifications from the network.
   1663      * Message.obj will contain an AsyncResult.
   1664      * AsyncResult.result will be a SuppServiceNotification instance.
   1665      *
   1666      * @param h Handler that receives the notification message.
   1667      * @param what User-defined message code.
   1668      * @param obj User object.
   1669      */
   1670 
   1671     public void registerForSignalInfo(Handler h, int what, Object obj){
   1672         mSignalInfoRegistrants.addUnique(h, what, obj);
   1673     }
   1674 
   1675     /**
   1676      * Unregisters for signal information notifications.
   1677      * Extraneous calls are tolerated silently
   1678      *
   1679      * @param h Handler to be removed from the registrant list.
   1680      */
   1681     public void unregisterForSignalInfo(Handler h){
   1682         mSignalInfoRegistrants.remove(h);
   1683     }
   1684 
   1685     /**
   1686      * Register for display information notifications from the network.
   1687      * Message.obj will contain an AsyncResult.
   1688      * AsyncResult.result will be a SuppServiceNotification instance.
   1689      *
   1690      * @param h Handler that receives the notification message.
   1691      * @param what User-defined message code.
   1692      * @param obj User object.
   1693      */
   1694     public void registerForDisplayInfo(Handler h, int what, Object obj){
   1695         mDisplayInfoRegistrants.addUnique(h, what, obj);
   1696     }
   1697 
   1698     /**
   1699      * Unregisters for display information notifications.
   1700      * Extraneous calls are tolerated silently
   1701      *
   1702      * @param h Handler to be removed from the registrant list.
   1703      */
   1704     public void unregisterForDisplayInfo(Handler h) {
   1705         mDisplayInfoRegistrants.remove(h);
   1706     }
   1707 
   1708     /**
   1709      * Register for notifications when CDMA OTA Provision status change
   1710      *
   1711      * @param h Handler that receives the notification message.
   1712      * @param what User-defined message code.
   1713      * @param obj User object.
   1714      */
   1715     public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj){
   1716         mCdmaOtaStatusChangeRegistrants.addUnique(h, what, obj);
   1717     }
   1718 
   1719     /**
   1720      * Unregister for notifications when CDMA OTA Provision status change
   1721      * @param h Handler to be removed from the registrant list.
   1722      */
   1723     public void unregisterForCdmaOtaStatusChange(Handler h){
   1724         mCdmaOtaStatusChangeRegistrants.remove(h);
   1725     }
   1726 
   1727     /**
   1728      * Registration point for subscription info ready
   1729      * @param h handler to notify
   1730      * @param what what code of message when delivered
   1731      * @param obj placed in Message.obj
   1732      */
   1733     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj){
   1734         mSubscriptionInfoReadyRegistrants.addUnique(h, what, obj);
   1735     }
   1736 
   1737     /**
   1738      * Unregister for notifications for subscription info
   1739      * @param h Handler to be removed from the registrant list.
   1740      */
   1741     public void unregisterForSubscriptionInfoReady(Handler h){
   1742         mSubscriptionInfoReadyRegistrants.remove(h);
   1743     }
   1744 
   1745     /**
   1746      * Sets an event to be fired when the telephony system processes
   1747      * a post-dial character on an outgoing call.<p>
   1748      *
   1749      * Messages of type <code>what</code> will be sent to <code>h</code>.
   1750      * The <code>obj</code> field of these Message's will be instances of
   1751      * <code>AsyncResult</code>. <code>Message.obj.result</code> will be
   1752      * a Connection object.<p>
   1753      *
   1754      * Message.arg1 will be the post dial character being processed,
   1755      * or 0 ('\0') if end of string.<p>
   1756      *
   1757      * If Connection.getPostDialState() == WAIT,
   1758      * the application must call
   1759      * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar()
   1760      * Connection.proceedAfterWaitChar()} or
   1761      * {@link com.android.internal.telephony.Connection#cancelPostDial()
   1762      * Connection.cancelPostDial()}
   1763      * for the telephony system to continue playing the post-dial
   1764      * DTMF sequence.<p>
   1765      *
   1766      * If Connection.getPostDialState() == WILD,
   1767      * the application must call
   1768      * {@link com.android.internal.telephony.Connection#proceedAfterWildChar
   1769      * Connection.proceedAfterWildChar()}
   1770      * or
   1771      * {@link com.android.internal.telephony.Connection#cancelPostDial()
   1772      * Connection.cancelPostDial()}
   1773      * for the telephony system to continue playing the
   1774      * post-dial DTMF sequence.<p>
   1775      *
   1776      */
   1777     public void registerForPostDialCharacter(Handler h, int what, Object obj){
   1778         mPostDialCharacterRegistrants.addUnique(h, what, obj);
   1779     }
   1780 
   1781     public void unregisterForPostDialCharacter(Handler h){
   1782         mPostDialCharacterRegistrants.remove(h);
   1783     }
   1784 
   1785     /**
   1786      * Register for TTY mode change notifications from the network.
   1787      * Message.obj will contain an AsyncResult.
   1788      * AsyncResult.result will be an Integer containing new mode.
   1789      *
   1790      * @param h Handler that receives the notification message.
   1791      * @param what User-defined message code.
   1792      * @param obj User object.
   1793      */
   1794     public void registerForTtyModeReceived(Handler h, int what, Object obj){
   1795         mTtyModeReceivedRegistrants.addUnique(h, what, obj);
   1796     }
   1797 
   1798     /**
   1799      * Unregisters for TTY mode change notifications.
   1800      * Extraneous calls are tolerated silently
   1801      *
   1802      * @param h Handler to be removed from the registrant list.
   1803      */
   1804     public void unregisterForTtyModeReceived(Handler h) {
   1805         mTtyModeReceivedRegistrants.remove(h);
   1806     }
   1807 
   1808     /* APIs to access foregroudCalls, backgroudCalls, and ringingCalls
   1809      * 1. APIs to access list of calls
   1810      * 2. APIs to check if any active call, which has connection other than
   1811      * disconnected ones, pleaser refer to Call.isIdle()
   1812      * 3. APIs to return first active call
   1813      * 4. APIs to return the connections of first active call
   1814      * 5. APIs to return other property of first active call
   1815      */
   1816 
   1817     /**
   1818      * @return list of all ringing calls
   1819      */
   1820     public List<Call> getRingingCalls() {
   1821         return Collections.unmodifiableList(mRingingCalls);
   1822     }
   1823 
   1824     /**
   1825      * @return list of all foreground calls
   1826      */
   1827     public List<Call> getForegroundCalls() {
   1828         return Collections.unmodifiableList(mForegroundCalls);
   1829     }
   1830 
   1831     /**
   1832      * @return list of all background calls
   1833      */
   1834     public List<Call> getBackgroundCalls() {
   1835         return Collections.unmodifiableList(mBackgroundCalls);
   1836     }
   1837 
   1838     /**
   1839      * Return true if there is at least one active foreground call
   1840      */
   1841     public boolean hasActiveFgCall() {
   1842         return (getFirstActiveCall(mForegroundCalls) != null);
   1843     }
   1844 
   1845     /**
   1846      * Return true if there is at least one active foreground call
   1847      * on a particular subId or an active sip call
   1848      */
   1849     public boolean hasActiveFgCall(int subId) {
   1850         return (getFirstActiveCall(mForegroundCalls, subId) != null);
   1851     }
   1852 
   1853     /**
   1854      * Return true if there is at least one active background call
   1855      */
   1856     public boolean hasActiveBgCall() {
   1857         // TODO since hasActiveBgCall may get called often
   1858         // better to cache it to improve performance
   1859         return (getFirstActiveCall(mBackgroundCalls) != null);
   1860     }
   1861 
   1862     /**
   1863      * Return true if there is at least one active background call
   1864      * on a particular subId or an active sip call
   1865      */
   1866     public boolean hasActiveBgCall(int subId) {
   1867         // TODO since hasActiveBgCall may get called often
   1868         // better to cache it to improve performance
   1869         return (getFirstActiveCall(mBackgroundCalls, subId) != null);
   1870     }
   1871 
   1872     /**
   1873      * Return true if there is at least one active ringing call
   1874      *
   1875      */
   1876     public boolean hasActiveRingingCall() {
   1877         return (getFirstActiveCall(mRingingCalls) != null);
   1878     }
   1879 
   1880     /**
   1881      * Return true if there is at least one active ringing call
   1882      */
   1883     public boolean hasActiveRingingCall(int subId) {
   1884         return (getFirstActiveCall(mRingingCalls, subId) != null);
   1885     }
   1886 
   1887     /**
   1888      * return the active foreground call from foreground calls
   1889      *
   1890      * Active call means the call is NOT in Call.State.IDLE
   1891      *
   1892      * 1. If there is active foreground call, return it
   1893      * 2. If there is no active foreground call, return the
   1894      *    foreground call associated with default phone, which state is IDLE.
   1895      * 3. If there is no phone registered at all, return null.
   1896      *
   1897      */
   1898     public Call getActiveFgCall() {
   1899         Call call = getFirstNonIdleCall(mForegroundCalls);
   1900         if (call == null) {
   1901             call = (mDefaultPhone == null)
   1902                     ? null
   1903                     : mDefaultPhone.getForegroundCall();
   1904         }
   1905         return call;
   1906     }
   1907 
   1908     public Call getActiveFgCall(int subId) {
   1909         Call call = getFirstNonIdleCall(mForegroundCalls, subId);
   1910         if (call == null) {
   1911             Phone phone = getPhone(subId);
   1912             call = (phone == null)
   1913                     ? null
   1914                     : phone.getForegroundCall();
   1915         }
   1916         return call;
   1917     }
   1918 
   1919     // Returns the first call that is not in IDLE state. If both active calls
   1920     // and disconnecting/disconnected calls exist, return the first active call.
   1921     private Call getFirstNonIdleCall(List<Call> calls) {
   1922         Call result = null;
   1923         for (Call call : calls) {
   1924             if (!call.isIdle()) {
   1925                 return call;
   1926             } else if (call.getState() != Call.State.IDLE) {
   1927                 if (result == null) result = call;
   1928             }
   1929         }
   1930         return result;
   1931     }
   1932 
   1933     // Returns the first call that is not in IDLE state. If both active calls
   1934     // and disconnecting/disconnected calls exist, return the first active call.
   1935     private Call getFirstNonIdleCall(List<Call> calls, int subId) {
   1936         Call result = null;
   1937         for (Call call : calls) {
   1938             if ((call.getPhone().getSubId() == subId) ||
   1939                     (call.getPhone() instanceof SipPhone)) {
   1940                 if (!call.isIdle()) {
   1941                     return call;
   1942                 } else if (call.getState() != Call.State.IDLE) {
   1943                     if (result == null) result = call;
   1944                 }
   1945             }
   1946         }
   1947         return result;
   1948     }
   1949 
   1950     /**
   1951      * return one active background call from background calls
   1952      *
   1953      * Active call means the call is NOT idle defined by Call.isIdle()
   1954      *
   1955      * 1. If there is only one active background call, return it
   1956      * 2. If there is more than one active background call, return the first one
   1957      * 3. If there is no active background call, return the background call
   1958      *    associated with default phone, which state is IDLE.
   1959      * 4. If there is no background call at all, return null.
   1960      *
   1961      * Complete background calls list can be get by getBackgroundCalls()
   1962      */
   1963     public Call getFirstActiveBgCall() {
   1964         Call call = getFirstNonIdleCall(mBackgroundCalls);
   1965         if (call == null) {
   1966             call = (mDefaultPhone == null)
   1967                     ? null
   1968                     : mDefaultPhone.getBackgroundCall();
   1969         }
   1970         return call;
   1971     }
   1972 
   1973     /**
   1974      * return one active background call from background calls of the
   1975      * requested subId.
   1976      *
   1977      * Active call means the call is NOT idle defined by Call.isIdle()
   1978      *
   1979      * 1. If there is only one active background call on given sub or
   1980      *    on SIP Phone, return it
   1981      * 2. If there is more than one active background call, return the background call
   1982      *    associated with the active sub.
   1983      * 3. If there is no background call at all, return null.
   1984      *
   1985      * Complete background calls list can be get by getBackgroundCalls()
   1986      */
   1987     public Call getFirstActiveBgCall(int subId) {
   1988         Phone phone = getPhone(subId);
   1989         if (hasMoreThanOneHoldingCall(subId)) {
   1990             return phone.getBackgroundCall();
   1991         } else {
   1992             Call call = getFirstNonIdleCall(mBackgroundCalls, subId);
   1993             if (call == null) {
   1994                 call = (phone == null)
   1995                         ? null
   1996                         : phone.getBackgroundCall();
   1997             }
   1998             return call;
   1999         }
   2000     }
   2001 
   2002     /**
   2003      * return one active ringing call from ringing calls
   2004      *
   2005      * Active call means the call is NOT idle defined by Call.isIdle()
   2006      *
   2007      * 1. If there is only one active ringing call, return it
   2008      * 2. If there is more than one active ringing call, return the first one
   2009      * 3. If there is no active ringing call, return the ringing call
   2010      *    associated with default phone, which state is IDLE.
   2011      * 4. If there is no ringing call at all, return null.
   2012      *
   2013      * Complete ringing calls list can be get by getRingingCalls()
   2014      */
   2015     public Call getFirstActiveRingingCall() {
   2016         Call call = getFirstNonIdleCall(mRingingCalls);
   2017         if (call == null) {
   2018             call = (mDefaultPhone == null)
   2019                     ? null
   2020                     : mDefaultPhone.getRingingCall();
   2021         }
   2022         return call;
   2023     }
   2024 
   2025     public Call getFirstActiveRingingCall(int subId) {
   2026         Phone phone = getPhone(subId);
   2027         Call call = getFirstNonIdleCall(mRingingCalls, subId);
   2028         if (call == null) {
   2029             call = (phone == null)
   2030                     ? null
   2031                     : phone.getRingingCall();
   2032         }
   2033         return call;
   2034     }
   2035 
   2036     /**
   2037      * @return the state of active foreground call
   2038      * return IDLE if there is no active foreground call
   2039      */
   2040     public Call.State getActiveFgCallState() {
   2041         Call fgCall = getActiveFgCall();
   2042 
   2043         if (fgCall != null) {
   2044             return fgCall.getState();
   2045         }
   2046 
   2047         return Call.State.IDLE;
   2048     }
   2049 
   2050     public Call.State getActiveFgCallState(int subId) {
   2051         Call fgCall = getActiveFgCall(subId);
   2052 
   2053         if (fgCall != null) {
   2054             return fgCall.getState();
   2055         }
   2056 
   2057         return Call.State.IDLE;
   2058     }
   2059 
   2060     /**
   2061      * @return the connections of active foreground call
   2062      * return empty list if there is no active foreground call
   2063      */
   2064     public List<Connection> getFgCallConnections() {
   2065         Call fgCall = getActiveFgCall();
   2066         if ( fgCall != null) {
   2067             return fgCall.getConnections();
   2068         }
   2069         return mEmptyConnections;
   2070     }
   2071 
   2072     /**
   2073      * @return the connections of active foreground call
   2074      * return empty list if there is no active foreground call
   2075      */
   2076     public List<Connection> getFgCallConnections(int subId) {
   2077         Call fgCall = getActiveFgCall(subId);
   2078         if ( fgCall != null) {
   2079             return fgCall.getConnections();
   2080         }
   2081         return mEmptyConnections;
   2082     }
   2083 
   2084     /**
   2085      * @return the connections of active background call
   2086      * return empty list if there is no active background call
   2087      */
   2088     public List<Connection> getBgCallConnections() {
   2089         Call bgCall = getFirstActiveBgCall();
   2090         if ( bgCall != null) {
   2091             return bgCall.getConnections();
   2092         }
   2093         return mEmptyConnections;
   2094     }
   2095 
   2096     /**
   2097      * @return the connections of active background call
   2098      * return empty list if there is no active background call
   2099      */
   2100     public List<Connection> getBgCallConnections(int subId) {
   2101         Call bgCall = getFirstActiveBgCall(subId);
   2102         if ( bgCall != null) {
   2103             return bgCall.getConnections();
   2104         }
   2105         return mEmptyConnections;
   2106     }
   2107 
   2108     /**
   2109      * @return the latest connection of active foreground call
   2110      * return null if there is no active foreground call
   2111      */
   2112     public Connection getFgCallLatestConnection() {
   2113         Call fgCall = getActiveFgCall();
   2114         if ( fgCall != null) {
   2115             return fgCall.getLatestConnection();
   2116         }
   2117         return null;
   2118     }
   2119 
   2120     /**
   2121      * @return the latest connection of active foreground call
   2122      * return null if there is no active foreground call
   2123      */
   2124     public Connection getFgCallLatestConnection(int subId) {
   2125         Call fgCall = getActiveFgCall(subId);
   2126         if ( fgCall != null) {
   2127             return fgCall.getLatestConnection();
   2128         }
   2129         return null;
   2130     }
   2131 
   2132     /**
   2133      * @return true if there is at least one Foreground call in disconnected state
   2134      */
   2135     public boolean hasDisconnectedFgCall() {
   2136         return (getFirstCallOfState(mForegroundCalls, Call.State.DISCONNECTED) != null);
   2137     }
   2138 
   2139     /**
   2140      * @return true if there is at least one Foreground call in disconnected state
   2141      */
   2142     public boolean hasDisconnectedFgCall(int subId) {
   2143         return (getFirstCallOfState(mForegroundCalls, Call.State.DISCONNECTED,
   2144                 subId) != null);
   2145     }
   2146 
   2147     /**
   2148      * @return true if there is at least one background call in disconnected state
   2149      */
   2150     public boolean hasDisconnectedBgCall() {
   2151         return (getFirstCallOfState(mBackgroundCalls, Call.State.DISCONNECTED) != null);
   2152     }
   2153 
   2154     /**
   2155      * @return true if there is at least one background call in disconnected state
   2156      */
   2157     public boolean hasDisconnectedBgCall(int subId) {
   2158         return (getFirstCallOfState(mBackgroundCalls, Call.State.DISCONNECTED,
   2159                 subId) != null);
   2160     }
   2161 
   2162 
   2163     /**
   2164      * @return the first active call from a call list
   2165      */
   2166     private  Call getFirstActiveCall(ArrayList<Call> calls) {
   2167         for (Call call : calls) {
   2168             if (!call.isIdle()) {
   2169                 return call;
   2170             }
   2171         }
   2172         return null;
   2173     }
   2174 
   2175     /**
   2176      * @return the first active call from a call list
   2177      */
   2178     private  Call getFirstActiveCall(ArrayList<Call> calls, int subId) {
   2179         for (Call call : calls) {
   2180             if ((!call.isIdle()) && ((call.getPhone().getSubId() == subId) ||
   2181                     (call.getPhone() instanceof SipPhone))) {
   2182                 return call;
   2183             }
   2184         }
   2185         return null;
   2186     }
   2187 
   2188     /**
   2189      * @return the first call in a the Call.state from a call list
   2190      */
   2191     private Call getFirstCallOfState(ArrayList<Call> calls, Call.State state) {
   2192         for (Call call : calls) {
   2193             if (call.getState() == state) {
   2194                 return call;
   2195             }
   2196         }
   2197         return null;
   2198     }
   2199 
   2200     /**
   2201      * @return the first call in a the Call.state from a call list
   2202      */
   2203     private Call getFirstCallOfState(ArrayList<Call> calls, Call.State state,
   2204             int subId) {
   2205         for (Call call : calls) {
   2206             if ((call.getState() == state) ||
   2207                 ((call.getPhone().getSubId() == subId) ||
   2208                 (call.getPhone() instanceof SipPhone))) {
   2209                 return call;
   2210             }
   2211         }
   2212         return null;
   2213     }
   2214 
   2215     private boolean hasMoreThanOneRingingCall() {
   2216         int count = 0;
   2217         for (Call call : mRingingCalls) {
   2218             if (call.getState().isRinging()) {
   2219                 if (++count > 1) return true;
   2220             }
   2221         }
   2222         return false;
   2223     }
   2224 
   2225     /**
   2226      * @return true if more than one active ringing call exists on
   2227      * the active subId.
   2228      * This checks for the active calls on provided
   2229      * subId and also active calls on SIP Phone.
   2230      *
   2231      */
   2232     private boolean hasMoreThanOneRingingCall(int subId) {
   2233         int count = 0;
   2234         for (Call call : mRingingCalls) {
   2235             if ((call.getState().isRinging()) &&
   2236                 ((call.getPhone().getSubId() == subId) ||
   2237                 (call.getPhone() instanceof SipPhone))) {
   2238                 if (++count > 1) return true;
   2239             }
   2240         }
   2241         return false;
   2242     }
   2243 
   2244     /**
   2245      * @return true if more than one active background call exists on
   2246      * the provided subId.
   2247      * This checks for the background calls on provided
   2248      * subId and also background calls on SIP Phone.
   2249      *
   2250      */
   2251     private boolean hasMoreThanOneHoldingCall(int subId) {
   2252         int count = 0;
   2253         for (Call call : mBackgroundCalls) {
   2254             if ((call.getState() == Call.State.HOLDING) &&
   2255                 ((call.getPhone().getSubId() == subId) ||
   2256                 (call.getPhone() instanceof SipPhone))) {
   2257                 if (++count > 1) return true;
   2258             }
   2259         }
   2260         return false;
   2261     }
   2262 
   2263     /* FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
   2264     private boolean isServiceStateInService() {
   2265         boolean bInService = false;
   2266 
   2267         for (Phone phone : mPhones) {
   2268             bInService = (phone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);
   2269             if (bInService) {
   2270                 break;
   2271             }
   2272         }
   2273 
   2274         if (VDBG) Rlog.d(LOG_TAG, "[isServiceStateInService] bInService = " + bInService);
   2275         return bInService;
   2276     }
   2277     */
   2278 
   2279     private class CallManagerHandler extends Handler {
   2280         @Override
   2281         public void handleMessage(Message msg) {
   2282 
   2283             switch (msg.what) {
   2284                 case EVENT_DISCONNECT:
   2285                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_DISCONNECT)");
   2286                     mDisconnectRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2287                     // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
   2288                     //mIsEccDialing = false;
   2289                     break;
   2290                 case EVENT_PRECISE_CALL_STATE_CHANGED:
   2291                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_PRECISE_CALL_STATE_CHANGED)");
   2292                     mPreciseCallStateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2293                     break;
   2294                 case EVENT_NEW_RINGING_CONNECTION:
   2295                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_NEW_RINGING_CONNECTION)");
   2296                     Connection c = (Connection) ((AsyncResult) msg.obj).result;
   2297                     int subId = c.getCall().getPhone().getSubId();
   2298                     if (getActiveFgCallState(subId).isDialing() || hasMoreThanOneRingingCall()) {
   2299                         try {
   2300                             Rlog.d(LOG_TAG, "silently drop incoming call: " + c.getCall());
   2301                             c.getCall().hangup();
   2302                         } catch (CallStateException e) {
   2303                             Rlog.w(LOG_TAG, "new ringing connection", e);
   2304                         }
   2305                     } else {
   2306                         mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2307                     }
   2308                     break;
   2309                 case EVENT_UNKNOWN_CONNECTION:
   2310                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_UNKNOWN_CONNECTION)");
   2311                     mUnknownConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2312                     break;
   2313                 case EVENT_INCOMING_RING:
   2314                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_INCOMING_RING)");
   2315                     // The event may come from RIL who's not aware of an ongoing fg call
   2316                     if (!hasActiveFgCall()) {
   2317                         mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2318                     }
   2319                     break;
   2320                 case EVENT_RINGBACK_TONE:
   2321                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_RINGBACK_TONE)");
   2322                     mRingbackToneRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2323                     break;
   2324                 case EVENT_IN_CALL_VOICE_PRIVACY_ON:
   2325                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_ON)");
   2326                     mInCallVoicePrivacyOnRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2327                     break;
   2328                 case EVENT_IN_CALL_VOICE_PRIVACY_OFF:
   2329                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_OFF)");
   2330                     mInCallVoicePrivacyOffRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2331                     break;
   2332                 case EVENT_CALL_WAITING:
   2333                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_CALL_WAITING)");
   2334                     mCallWaitingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2335                     break;
   2336                 case EVENT_DISPLAY_INFO:
   2337                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_DISPLAY_INFO)");
   2338                     mDisplayInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2339                     break;
   2340                 case EVENT_SIGNAL_INFO:
   2341                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_SIGNAL_INFO)");
   2342                     mSignalInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2343                     break;
   2344                 case EVENT_CDMA_OTA_STATUS_CHANGE:
   2345                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_CDMA_OTA_STATUS_CHANGE)");
   2346                     mCdmaOtaStatusChangeRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2347                     break;
   2348                 case EVENT_RESEND_INCALL_MUTE:
   2349                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_RESEND_INCALL_MUTE)");
   2350                     mResendIncallMuteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2351                     break;
   2352                 case EVENT_MMI_INITIATE:
   2353                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_MMI_INITIATE)");
   2354                     mMmiInitiateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2355                     break;
   2356                 case EVENT_MMI_COMPLETE:
   2357                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_MMI_COMPLETE)");
   2358                     mMmiCompleteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2359                     break;
   2360                 case EVENT_ECM_TIMER_RESET:
   2361                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_ECM_TIMER_RESET)");
   2362                     mEcmTimerResetRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2363                     break;
   2364                 case EVENT_SUBSCRIPTION_INFO_READY:
   2365                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_SUBSCRIPTION_INFO_READY)");
   2366                     mSubscriptionInfoReadyRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2367                     break;
   2368                 case EVENT_SUPP_SERVICE_FAILED:
   2369                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_SUPP_SERVICE_FAILED)");
   2370                     mSuppServiceFailedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2371                     break;
   2372                 case EVENT_SERVICE_STATE_CHANGED:
   2373                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_SERVICE_STATE_CHANGED)");
   2374                     mServiceStateChangedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2375                     // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
   2376                     //setAudioMode();
   2377                     break;
   2378                 case EVENT_POST_DIAL_CHARACTER:
   2379                     // we need send the character that is being processed in msg.arg1
   2380                     // so can't use notifyRegistrants()
   2381                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_POST_DIAL_CHARACTER)");
   2382                     for(int i=0; i < mPostDialCharacterRegistrants.size(); i++) {
   2383                         Message notifyMsg;
   2384                         notifyMsg = ((Registrant)mPostDialCharacterRegistrants.get(i)).messageForRegistrant();
   2385                         notifyMsg.obj = msg.obj;
   2386                         notifyMsg.arg1 = msg.arg1;
   2387                         notifyMsg.sendToTarget();
   2388                     }
   2389                     break;
   2390                 case EVENT_ONHOLD_TONE:
   2391                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_ONHOLD_TONE)");
   2392                     mOnHoldToneRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2393                     break;
   2394                 case EVENT_TTY_MODE_RECEIVED:
   2395                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_TTY_MODE_RECEIVED)");
   2396                     mTtyModeReceivedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   2397                     break;
   2398                 /* FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
   2399                 case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
   2400                     if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_RADIO_OFF_OR_NOT_AVAILABLE)");
   2401                     setAudioMode();
   2402                     break;
   2403                 */
   2404             }
   2405         }
   2406     };
   2407 
   2408     @Override
   2409     public String toString() {
   2410         Call call;
   2411         StringBuilder b = new StringBuilder();
   2412         for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
   2413             b.append("CallManager {");
   2414             b.append("\nstate = " + getState(i));
   2415             call = getActiveFgCall(i);
   2416             if (call != null) {
   2417                 b.append("\n- Foreground: " + getActiveFgCallState(i));
   2418                 b.append(" from " + call.getPhone());
   2419                 b.append("\n  Conn: ").append(getFgCallConnections(i));
   2420             }
   2421             call = getFirstActiveBgCall(i);
   2422             if (call != null) {
   2423                 b.append("\n- Background: " + call.getState());
   2424                 b.append(" from " + call.getPhone());
   2425                 b.append("\n  Conn: ").append(getBgCallConnections(i));
   2426             }
   2427             call = getFirstActiveRingingCall(i);
   2428             if (call != null) {
   2429                 b.append("\n- Ringing: " +call.getState());
   2430                 b.append(" from " + call.getPhone());
   2431             }
   2432         }
   2433 
   2434         for (Phone phone : getAllPhones()) {
   2435             if (phone != null) {
   2436                 b.append("\nPhone: " + phone + ", name = " + phone.getPhoneName()
   2437                         + ", state = " + phone.getState());
   2438                 call = phone.getForegroundCall();
   2439                 if (call != null) {
   2440                     b.append("\n- Foreground: ").append(call);
   2441                 }
   2442                 call = phone.getBackgroundCall();
   2443                 if (call != null) {
   2444                     b.append(" Background: ").append(call);
   2445                 }
   2446                 call = phone.getRingingCall();
   2447                 if (call != null) {
   2448                     b.append(" Ringing: ").append(call);
   2449                 }
   2450             }
   2451         }
   2452         b.append("\n}");
   2453         return b.toString();
   2454     }
   2455 }
   2456