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