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.sip.SipPhone;
     20 
     21 import android.content.Context;
     22 import android.media.AudioManager;
     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.telephony.PhoneStateListener;
     29 import android.telephony.ServiceState;
     30 import android.util.Log;
     31 
     32 import java.util.ArrayList;
     33 import java.util.Collections;
     34 import java.util.List;
     35 
     36 
     37 
     38 /**
     39  * @hide
     40  *
     41  * CallManager class provides an abstract layer for PhoneApp to access
     42  * and control calls. It implements Phone interface.
     43  *
     44  * CallManager provides call and connection control as well as
     45  * channel capability.
     46  *
     47  * There are three categories of APIs CallManager provided
     48  *
     49  *  1. Call control and operation, such as dial() and hangup()
     50  *  2. Channel capabilities, such as CanConference()
     51  *  3. Register notification
     52  *
     53  *
     54  */
     55 public final class CallManager {
     56 
     57     private static final String LOG_TAG ="CallManager";
     58     private static final boolean DBG = true;
     59     private static final boolean VDBG = false;
     60 
     61     private static final int EVENT_DISCONNECT = 100;
     62     private static final int EVENT_PRECISE_CALL_STATE_CHANGED = 101;
     63     private static final int EVENT_NEW_RINGING_CONNECTION = 102;
     64     private static final int EVENT_UNKNOWN_CONNECTION = 103;
     65     private static final int EVENT_INCOMING_RING = 104;
     66     private static final int EVENT_RINGBACK_TONE = 105;
     67     private static final int EVENT_IN_CALL_VOICE_PRIVACY_ON = 106;
     68     private static final int EVENT_IN_CALL_VOICE_PRIVACY_OFF = 107;
     69     private static final int EVENT_CALL_WAITING = 108;
     70     private static final int EVENT_DISPLAY_INFO = 109;
     71     private static final int EVENT_SIGNAL_INFO = 110;
     72     private static final int EVENT_CDMA_OTA_STATUS_CHANGE = 111;
     73     private static final int EVENT_RESEND_INCALL_MUTE = 112;
     74     private static final int EVENT_MMI_INITIATE = 113;
     75     private static final int EVENT_MMI_COMPLETE = 114;
     76     private static final int EVENT_ECM_TIMER_RESET = 115;
     77     private static final int EVENT_SUBSCRIPTION_INFO_READY = 116;
     78     private static final int EVENT_SUPP_SERVICE_FAILED = 117;
     79     private static final int EVENT_SERVICE_STATE_CHANGED = 118;
     80     private static final int EVENT_POST_DIAL_CHARACTER = 119;
     81 
     82     // Singleton instance
     83     private static final CallManager INSTANCE = new CallManager();
     84 
     85     // list of registered phones, which are PhoneBase objs
     86     private final ArrayList<Phone> mPhones;
     87 
     88     // list of supported ringing calls
     89     private final ArrayList<Call> mRingingCalls;
     90 
     91     // list of supported background calls
     92     private final ArrayList<Call> mBackgroundCalls;
     93 
     94     // list of supported foreground calls
     95     private final ArrayList<Call> mForegroundCalls;
     96 
     97     // empty connection list
     98     private final ArrayList<Connection> emptyConnections = new ArrayList<Connection>();
     99 
    100     // default phone as the first phone registered, which is PhoneBase obj
    101     private Phone mDefaultPhone;
    102 
    103     // state registrants
    104     protected final RegistrantList mPreciseCallStateRegistrants
    105     = new RegistrantList();
    106 
    107     protected final RegistrantList mNewRingingConnectionRegistrants
    108     = new RegistrantList();
    109 
    110     protected final RegistrantList mIncomingRingRegistrants
    111     = new RegistrantList();
    112 
    113     protected final RegistrantList mDisconnectRegistrants
    114     = new RegistrantList();
    115 
    116     protected final RegistrantList mMmiRegistrants
    117     = new RegistrantList();
    118 
    119     protected final RegistrantList mUnknownConnectionRegistrants
    120     = new RegistrantList();
    121 
    122     protected final RegistrantList mRingbackToneRegistrants
    123     = new RegistrantList();
    124 
    125     protected final RegistrantList mInCallVoicePrivacyOnRegistrants
    126     = new RegistrantList();
    127 
    128     protected final RegistrantList mInCallVoicePrivacyOffRegistrants
    129     = new RegistrantList();
    130 
    131     protected final RegistrantList mCallWaitingRegistrants
    132     = new RegistrantList();
    133 
    134     protected final RegistrantList mDisplayInfoRegistrants
    135     = new RegistrantList();
    136 
    137     protected final RegistrantList mSignalInfoRegistrants
    138     = new RegistrantList();
    139 
    140     protected final RegistrantList mCdmaOtaStatusChangeRegistrants
    141     = new RegistrantList();
    142 
    143     protected final RegistrantList mResendIncallMuteRegistrants
    144     = new RegistrantList();
    145 
    146     protected final RegistrantList mMmiInitiateRegistrants
    147     = new RegistrantList();
    148 
    149     protected final RegistrantList mMmiCompleteRegistrants
    150     = new RegistrantList();
    151 
    152     protected final RegistrantList mEcmTimerResetRegistrants
    153     = new RegistrantList();
    154 
    155     protected final RegistrantList mSubscriptionInfoReadyRegistrants
    156     = new RegistrantList();
    157 
    158     protected final RegistrantList mSuppServiceFailedRegistrants
    159     = new RegistrantList();
    160 
    161     protected final RegistrantList mServiceStateChangedRegistrants
    162     = new RegistrantList();
    163 
    164     protected final RegistrantList mPostDialCharacterRegistrants
    165     = new RegistrantList();
    166 
    167     private CallManager() {
    168         mPhones = new ArrayList<Phone>();
    169         mRingingCalls = new ArrayList<Call>();
    170         mBackgroundCalls = new ArrayList<Call>();
    171         mForegroundCalls = new ArrayList<Call>();
    172         mDefaultPhone = null;
    173     }
    174 
    175     /**
    176      * get singleton instance of CallManager
    177      * @return CallManager
    178      */
    179     public static CallManager getInstance() {
    180         return INSTANCE;
    181     }
    182 
    183     /**
    184      * Get the corresponding PhoneBase obj
    185      *
    186      * @param phone a Phone object
    187      * @return the corresponding PhoneBase obj in Phone if Phone
    188      * is a PhoneProxy obj
    189      * or the Phone itself if Phone is not a PhoneProxy obj
    190      */
    191     private static Phone getPhoneBase(Phone phone) {
    192         if (phone instanceof PhoneProxy) {
    193             return phone.getForegroundCall().getPhone();
    194         }
    195         return phone;
    196     }
    197 
    198     /**
    199      * Check if two phones refer to the same PhoneBase obj
    200      *
    201      * Note: PhoneBase, not PhoneProxy, is to be used inside of CallManager
    202      *
    203      * Both PhoneBase and PhoneProxy implement Phone interface, so
    204      * they have same phone APIs, such as dial(). The real implementation, for
    205      * example in GSM,  is in GSMPhone as extend from PhoneBase, so that
    206      * foregroundCall.getPhone() returns GSMPhone obj. On the other hand,
    207      * PhoneFactory.getDefaultPhone() returns PhoneProxy obj, which has a class
    208      * member of GSMPhone.
    209      *
    210      * So for phone returned by PhoneFacotry, which is used by PhoneApp,
    211      *        phone.getForegroundCall().getPhone() != phone
    212      * but
    213      *        isSamePhone(phone, phone.getForegroundCall().getPhone()) == true
    214      *
    215      * @param p1 is the first Phone obj
    216      * @param p2 is the second Phone obj
    217      * @return true if p1 and p2 refer to the same phone
    218      */
    219     public static boolean isSamePhone(Phone p1, Phone p2) {
    220         return (getPhoneBase(p1) == getPhoneBase(p2));
    221     }
    222 
    223     /**
    224      * Returns all the registered phone objects.
    225      * @return all the registered phone objects.
    226      */
    227     public List<Phone> getAllPhones() {
    228         return Collections.unmodifiableList(mPhones);
    229     }
    230 
    231     /**
    232      * Get current coarse-grained voice call state.
    233      * If the Call Manager has an active call and call waiting occurs,
    234      * then the phone state is RINGING not OFFHOOK
    235      *
    236      */
    237     public Phone.State getState() {
    238         Phone.State s = Phone.State.IDLE;
    239 
    240         for (Phone phone : mPhones) {
    241             if (phone.getState() == Phone.State.RINGING) {
    242                 s = Phone.State.RINGING;
    243             } else if (phone.getState() == Phone.State.OFFHOOK) {
    244                 if (s == Phone.State.IDLE) s = Phone.State.OFFHOOK;
    245             }
    246         }
    247         return s;
    248     }
    249 
    250     /**
    251      * @return the service state of CallManager, which represents the
    252      * highest priority state of all the service states of phones
    253      *
    254      * The priority is defined as
    255      *
    256      * STATE_IN_SERIVCE > STATE_OUT_OF_SERIVCE > STATE_EMERGENCY > STATE_POWER_OFF
    257      *
    258      */
    259 
    260     public int getServiceState() {
    261         int resultState = ServiceState.STATE_OUT_OF_SERVICE;
    262 
    263         for (Phone phone : mPhones) {
    264             int serviceState = phone.getServiceState().getState();
    265             if (serviceState == ServiceState.STATE_IN_SERVICE) {
    266                 // IN_SERVICE has the highest priority
    267                 resultState = serviceState;
    268                 break;
    269             } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
    270                 // OUT_OF_SERVICE replaces EMERGENCY_ONLY and POWER_OFF
    271                 // Note: EMERGENCY_ONLY is not in use at this moment
    272                 if ( resultState == ServiceState.STATE_EMERGENCY_ONLY ||
    273                         resultState == ServiceState.STATE_POWER_OFF) {
    274                     resultState = serviceState;
    275                 }
    276             } else if (serviceState == ServiceState.STATE_EMERGENCY_ONLY) {
    277                 if (resultState == ServiceState.STATE_POWER_OFF) {
    278                     resultState = serviceState;
    279                 }
    280             }
    281         }
    282         return resultState;
    283     }
    284 
    285     /**
    286      * Register phone to CallManager
    287      * @param phone to be registered
    288      * @return true if register successfully
    289      */
    290     public boolean registerPhone(Phone phone) {
    291         Phone basePhone = getPhoneBase(phone);
    292 
    293         if (basePhone != null && !mPhones.contains(basePhone)) {
    294 
    295             if (DBG) {
    296                 Log.d(LOG_TAG, "registerPhone(" +
    297                         phone.getPhoneName() + " " + phone + ")");
    298             }
    299 
    300             if (mPhones.isEmpty()) {
    301                 mDefaultPhone = basePhone;
    302             }
    303             mPhones.add(basePhone);
    304             mRingingCalls.add(basePhone.getRingingCall());
    305             mBackgroundCalls.add(basePhone.getBackgroundCall());
    306             mForegroundCalls.add(basePhone.getForegroundCall());
    307             registerForPhoneStates(basePhone);
    308             return true;
    309         }
    310         return false;
    311     }
    312 
    313     /**
    314      * unregister phone from CallManager
    315      * @param phone to be unregistered
    316      */
    317     public void unregisterPhone(Phone phone) {
    318         Phone basePhone = getPhoneBase(phone);
    319 
    320         if (basePhone != null && mPhones.contains(basePhone)) {
    321 
    322             if (DBG) {
    323                 Log.d(LOG_TAG, "unregisterPhone(" +
    324                         phone.getPhoneName() + " " + phone + ")");
    325             }
    326 
    327             mPhones.remove(basePhone);
    328             mRingingCalls.remove(basePhone.getRingingCall());
    329             mBackgroundCalls.remove(basePhone.getBackgroundCall());
    330             mForegroundCalls.remove(basePhone.getForegroundCall());
    331             unregisterForPhoneStates(basePhone);
    332             if (basePhone == mDefaultPhone) {
    333                 if (mPhones.isEmpty()) {
    334                     mDefaultPhone = null;
    335                 } else {
    336                     mDefaultPhone = mPhones.get(0);
    337                 }
    338             }
    339         }
    340     }
    341 
    342     /**
    343      * return the default phone or null if no phone available
    344      */
    345     public Phone getDefaultPhone() {
    346         return mDefaultPhone;
    347     }
    348 
    349     /**
    350      * @return the phone associated with the foreground call
    351      */
    352     public Phone getFgPhone() {
    353         return getActiveFgCall().getPhone();
    354     }
    355 
    356     /**
    357      * @return the phone associated with the background call
    358      */
    359     public Phone getBgPhone() {
    360         return getFirstActiveBgCall().getPhone();
    361     }
    362 
    363     /**
    364      * @return the phone associated with the ringing call
    365      */
    366     public Phone getRingingPhone() {
    367         return getFirstActiveRingingCall().getPhone();
    368     }
    369 
    370     public void setAudioMode() {
    371         Context context = getContext();
    372         if (context == null) return;
    373         AudioManager audioManager = (AudioManager)
    374                 context.getSystemService(Context.AUDIO_SERVICE);
    375 
    376         // change the audio mode and request/abandon audio focus according to phone state,
    377         // but only on audio mode transitions
    378         switch (getState()) {
    379             case RINGING:
    380                 if (audioManager.getMode() != AudioManager.MODE_RINGTONE) {
    381                     // only request audio focus if the ringtone is going to be heard
    382                     if (audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0) {
    383                         if (VDBG) Log.d(LOG_TAG, "requestAudioFocus on STREAM_RING");
    384                         audioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
    385                                 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
    386                     }
    387                     audioManager.setMode(AudioManager.MODE_RINGTONE);
    388                 }
    389                 break;
    390             case OFFHOOK:
    391                 Phone offhookPhone = getFgPhone();
    392                 if (getActiveFgCallState() == Call.State.IDLE) {
    393                     // There is no active Fg calls, the OFFHOOK state
    394                     // is set by the Bg call. So set the phone to bgPhone.
    395                     offhookPhone = getBgPhone();
    396                 }
    397 
    398                 int newAudioMode = AudioManager.MODE_IN_CALL;
    399                 if (offhookPhone instanceof SipPhone) {
    400                     // enable IN_COMMUNICATION audio mode instead for sipPhone
    401                     newAudioMode = AudioManager.MODE_IN_COMMUNICATION;
    402                 }
    403                 if (audioManager.getMode() != newAudioMode) {
    404                     // request audio focus before setting the new mode
    405                     if (VDBG) Log.d(LOG_TAG, "requestAudioFocus on STREAM_VOICE_CALL");
    406                     audioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
    407                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
    408                     audioManager.setMode(newAudioMode);
    409                 }
    410                 break;
    411             case IDLE:
    412                 if (audioManager.getMode() != AudioManager.MODE_NORMAL) {
    413                     audioManager.setMode(AudioManager.MODE_NORMAL);
    414                     if (VDBG) Log.d(LOG_TAG, "abandonAudioFocus");
    415                     // abandon audio focus after the mode has been set back to normal
    416                     audioManager.abandonAudioFocusForCall();
    417                 }
    418                 break;
    419         }
    420     }
    421 
    422     private Context getContext() {
    423         Phone defaultPhone = getDefaultPhone();
    424         return ((defaultPhone == null) ? null : defaultPhone.getContext());
    425     }
    426 
    427     private void registerForPhoneStates(Phone phone) {
    428         // for common events supported by all phones
    429         phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
    430         phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
    431         phone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);
    432         phone.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION, null);
    433         phone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING, null);
    434         phone.registerForRingbackTone(mHandler, EVENT_RINGBACK_TONE, null);
    435         phone.registerForInCallVoicePrivacyOn(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);
    436         phone.registerForInCallVoicePrivacyOff(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);
    437         phone.registerForDisplayInfo(mHandler, EVENT_DISPLAY_INFO, null);
    438         phone.registerForSignalInfo(mHandler, EVENT_SIGNAL_INFO, null);
    439         phone.registerForResendIncallMute(mHandler, EVENT_RESEND_INCALL_MUTE, null);
    440         phone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);
    441         phone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);
    442         phone.registerForSuppServiceFailed(mHandler, EVENT_SUPP_SERVICE_FAILED, null);
    443         phone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, null);
    444 
    445         // for events supported only by GSM and CDMA phone
    446         if (phone.getPhoneType() == Phone.PHONE_TYPE_GSM ||
    447                 phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
    448             phone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL_CHARACTER, null);
    449         }
    450 
    451         // for events supported only by CDMA phone
    452         if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA ){
    453             phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
    454             phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);
    455             phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);
    456             phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);
    457         }
    458     }
    459 
    460     private void unregisterForPhoneStates(Phone phone) {
    461         //  for common events supported by all phones
    462         phone.unregisterForPreciseCallStateChanged(mHandler);
    463         phone.unregisterForDisconnect(mHandler);
    464         phone.unregisterForNewRingingConnection(mHandler);
    465         phone.unregisterForUnknownConnection(mHandler);
    466         phone.unregisterForIncomingRing(mHandler);
    467         phone.unregisterForRingbackTone(mHandler);
    468         phone.unregisterForInCallVoicePrivacyOn(mHandler);
    469         phone.unregisterForInCallVoicePrivacyOff(mHandler);
    470         phone.unregisterForDisplayInfo(mHandler);
    471         phone.unregisterForSignalInfo(mHandler);
    472         phone.unregisterForResendIncallMute(mHandler);
    473         phone.unregisterForMmiInitiate(mHandler);
    474         phone.unregisterForMmiComplete(mHandler);
    475         phone.unregisterForSuppServiceFailed(mHandler);
    476         phone.unregisterForServiceStateChanged(mHandler);
    477 
    478         // for events supported only by GSM and CDMA phone
    479         if (phone.getPhoneType() == Phone.PHONE_TYPE_GSM ||
    480                 phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
    481             phone.setOnPostDialCharacter(null, EVENT_POST_DIAL_CHARACTER, null);
    482         }
    483 
    484         // for events supported only by CDMA phone
    485         if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA ){
    486             phone.unregisterForCdmaOtaStatusChange(mHandler);
    487             phone.unregisterForSubscriptionInfoReady(mHandler);
    488             phone.unregisterForCallWaiting(mHandler);
    489             phone.unregisterForEcmTimerReset(mHandler);
    490         }
    491     }
    492 
    493     /**
    494      * Answers a ringing or waiting call.
    495      *
    496      * Active call, if any, go on hold.
    497      * If active call can't be held, i.e., a background call of the same channel exists,
    498      * the active call will be hang up.
    499      *
    500      * Answering occurs asynchronously, and final notification occurs via
    501      * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
    502      * java.lang.Object) registerForPreciseCallStateChanged()}.
    503      *
    504      * @exception CallStateException when call is not ringing or waiting
    505      */
    506     public void acceptCall(Call ringingCall) throws CallStateException {
    507         Phone ringingPhone = ringingCall.getPhone();
    508 
    509         if (VDBG) {
    510             Log.d(LOG_TAG, "acceptCall(" +ringingCall + " from " + ringingCall.getPhone() + ")");
    511             Log.d(LOG_TAG, this.toString());
    512         }
    513 
    514         if ( hasActiveFgCall() ) {
    515             Phone activePhone = getActiveFgCall().getPhone();
    516             boolean hasBgCall = ! (activePhone.getBackgroundCall().isIdle());
    517             boolean sameChannel = (activePhone == ringingPhone);
    518 
    519             if (VDBG) {
    520                 Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + "sameChannel:" + sameChannel);
    521             }
    522 
    523             if (sameChannel && hasBgCall) {
    524                 getActiveFgCall().hangup();
    525             } else if (!sameChannel && !hasBgCall) {
    526                 activePhone.switchHoldingAndActive();
    527             } else if (!sameChannel && hasBgCall) {
    528                 getActiveFgCall().hangup();
    529             }
    530         }
    531 
    532         ringingPhone.acceptCall();
    533 
    534         if (VDBG) {
    535             Log.d(LOG_TAG, "End acceptCall(" +ringingCall + ")");
    536             Log.d(LOG_TAG, this.toString());
    537         }
    538     }
    539 
    540     /**
    541      * Reject (ignore) a ringing call. In GSM, this means UDUB
    542      * (User Determined User Busy). Reject occurs asynchronously,
    543      * and final notification occurs via
    544      * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
    545      * java.lang.Object) registerForPreciseCallStateChanged()}.
    546      *
    547      * @exception CallStateException when no call is ringing or waiting
    548      */
    549     public void rejectCall(Call ringingCall) throws CallStateException {
    550         if (VDBG) {
    551             Log.d(LOG_TAG, "rejectCall(" +ringingCall + ")");
    552             Log.d(LOG_TAG, this.toString());
    553         }
    554 
    555         Phone ringingPhone = ringingCall.getPhone();
    556 
    557         ringingPhone.rejectCall();
    558 
    559         if (VDBG) {
    560             Log.d(LOG_TAG, "End rejectCall(" +ringingCall + ")");
    561             Log.d(LOG_TAG, this.toString());
    562         }
    563     }
    564 
    565     /**
    566      * Places active call on hold, and makes held call active.
    567      * Switch occurs asynchronously and may fail.
    568      *
    569      * There are 4 scenarios
    570      * 1. only active call but no held call, aka, hold
    571      * 2. no active call but only held call, aka, unhold
    572      * 3. both active and held calls from same phone, aka, swap
    573      * 4. active and held calls from different phones, aka, phone swap
    574      *
    575      * Final notification occurs via
    576      * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
    577      * java.lang.Object) registerForPreciseCallStateChanged()}.
    578      *
    579      * @exception CallStateException if active call is ringing, waiting, or
    580      * dialing/alerting, or heldCall can't be active.
    581      * In these cases, this operation may not be performed.
    582      */
    583     public void switchHoldingAndActive(Call heldCall) throws CallStateException {
    584         Phone activePhone = null;
    585         Phone heldPhone = null;
    586 
    587         if (VDBG) {
    588             Log.d(LOG_TAG, "switchHoldingAndActive(" +heldCall + ")");
    589             Log.d(LOG_TAG, this.toString());
    590         }
    591 
    592         if (hasActiveFgCall()) {
    593             activePhone = getActiveFgCall().getPhone();
    594         }
    595 
    596         if (heldCall != null) {
    597             heldPhone = heldCall.getPhone();
    598         }
    599 
    600         if (activePhone != null) {
    601             activePhone.switchHoldingAndActive();
    602         }
    603 
    604         if (heldPhone != null && heldPhone != activePhone) {
    605             heldPhone.switchHoldingAndActive();
    606         }
    607 
    608         if (VDBG) {
    609             Log.d(LOG_TAG, "End switchHoldingAndActive(" +heldCall + ")");
    610             Log.d(LOG_TAG, this.toString());
    611         }
    612     }
    613 
    614     /**
    615      * Hangup foreground call and resume the specific background call
    616      *
    617      * Note: this is noop if there is no foreground call or the heldCall is null
    618      *
    619      * @param heldCall to become foreground
    620      * @throws CallStateException
    621      */
    622     public void hangupForegroundResumeBackground(Call heldCall) throws CallStateException {
    623         Phone foregroundPhone = null;
    624         Phone backgroundPhone = null;
    625 
    626         if (VDBG) {
    627             Log.d(LOG_TAG, "hangupForegroundResumeBackground(" +heldCall + ")");
    628             Log.d(LOG_TAG, this.toString());
    629         }
    630 
    631         if (hasActiveFgCall()) {
    632             foregroundPhone = getFgPhone();
    633             if (heldCall != null) {
    634                 backgroundPhone = heldCall.getPhone();
    635                 if (foregroundPhone == backgroundPhone) {
    636                     getActiveFgCall().hangup();
    637                 } else {
    638                 // the call to be hangup and resumed belongs to different phones
    639                     getActiveFgCall().hangup();
    640                     switchHoldingAndActive(heldCall);
    641                 }
    642             }
    643         }
    644 
    645         if (VDBG) {
    646             Log.d(LOG_TAG, "End hangupForegroundResumeBackground(" +heldCall + ")");
    647             Log.d(LOG_TAG, this.toString());
    648         }
    649     }
    650 
    651     /**
    652      * Whether or not the phone can conference in the current phone
    653      * state--that is, one call holding and one call active.
    654      * @return true if the phone can conference; false otherwise.
    655      */
    656     public boolean canConference(Call heldCall) {
    657         Phone activePhone = null;
    658         Phone heldPhone = null;
    659 
    660         if (hasActiveFgCall()) {
    661             activePhone = getActiveFgCall().getPhone();
    662         }
    663 
    664         if (heldCall != null) {
    665             heldPhone = heldCall.getPhone();
    666         }
    667 
    668         return heldPhone.getClass().equals(activePhone.getClass());
    669     }
    670 
    671     /**
    672      * Conferences holding and active. Conference occurs asynchronously
    673      * and may fail. Final notification occurs via
    674      * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
    675      * java.lang.Object) registerForPreciseCallStateChanged()}.
    676      *
    677      * @exception CallStateException if canConference() would return false.
    678      * In these cases, this operation may not be performed.
    679      */
    680     public void conference(Call heldCall) throws CallStateException {
    681 
    682         if (VDBG) {
    683             Log.d(LOG_TAG, "conference(" +heldCall + ")");
    684             Log.d(LOG_TAG, this.toString());
    685         }
    686 
    687 
    688         Phone fgPhone = getFgPhone();
    689         if (fgPhone instanceof SipPhone) {
    690             ((SipPhone) fgPhone).conference(heldCall);
    691         } else if (canConference(heldCall)) {
    692             fgPhone.conference();
    693         } else {
    694             throw(new CallStateException("Can't conference foreground and selected background call"));
    695         }
    696 
    697         if (VDBG) {
    698             Log.d(LOG_TAG, "End conference(" +heldCall + ")");
    699             Log.d(LOG_TAG, this.toString());
    700         }
    701 
    702     }
    703 
    704     /**
    705      * Initiate a new voice connection. This happens asynchronously, so you
    706      * cannot assume the audio path is connected (or a call index has been
    707      * assigned) until PhoneStateChanged notification has occurred.
    708      *
    709      * @exception CallStateException if a new outgoing call is not currently
    710      * possible because no more call slots exist or a call exists that is
    711      * dialing, alerting, ringing, or waiting.  Other errors are
    712      * handled asynchronously.
    713      */
    714     public Connection dial(Phone phone, String dialString) throws CallStateException {
    715         Phone basePhone = getPhoneBase(phone);
    716         Connection result;
    717 
    718         if (VDBG) {
    719             Log.d(LOG_TAG, " dial(" + basePhone + ", "+ dialString + ")");
    720             Log.d(LOG_TAG, this.toString());
    721         }
    722 
    723         if (!canDial(phone)) {
    724             throw new CallStateException("cannot dial in current state");
    725         }
    726 
    727         if ( hasActiveFgCall() ) {
    728             Phone activePhone = getActiveFgCall().getPhone();
    729             boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());
    730 
    731             if (DBG) {
    732                 Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == basePhone));
    733             }
    734 
    735             if (activePhone != basePhone) {
    736                 if (hasBgCall) {
    737                     Log.d(LOG_TAG, "Hangup");
    738                     getActiveFgCall().hangup();
    739                 } else {
    740                     Log.d(LOG_TAG, "Switch");
    741                     activePhone.switchHoldingAndActive();
    742                 }
    743             }
    744         }
    745 
    746         result = basePhone.dial(dialString);
    747 
    748         if (VDBG) {
    749             Log.d(LOG_TAG, "End dial(" + basePhone + ", "+ dialString + ")");
    750             Log.d(LOG_TAG, this.toString());
    751         }
    752 
    753         return result;
    754     }
    755 
    756     /**
    757      * Initiate a new voice connection. This happens asynchronously, so you
    758      * cannot assume the audio path is connected (or a call index has been
    759      * assigned) until PhoneStateChanged notification has occurred.
    760      *
    761      * @exception CallStateException if a new outgoing call is not currently
    762      * possible because no more call slots exist or a call exists that is
    763      * dialing, alerting, ringing, or waiting.  Other errors are
    764      * handled asynchronously.
    765      */
    766     public Connection dial(Phone phone, String dialString, UUSInfo uusInfo) throws CallStateException {
    767         return phone.dial(dialString, uusInfo);
    768     }
    769 
    770     /**
    771      * clear disconnect connection for each phone
    772      */
    773     public void clearDisconnected() {
    774         for(Phone phone : mPhones) {
    775             phone.clearDisconnected();
    776         }
    777     }
    778 
    779     /**
    780      * Phone can make a call only if ALL of the following are true:
    781      *        - Phone is not powered off
    782      *        - There's no incoming or waiting call
    783      *        - There's available call slot in either foreground or background
    784      *        - The foreground call is ACTIVE or IDLE or DISCONNECTED.
    785      *          (We mainly need to make sure it *isn't* DIALING or ALERTING.)
    786      * @param phone
    787      * @return true if the phone can make a new call
    788      */
    789     private boolean canDial(Phone phone) {
    790         int serviceState = phone.getServiceState().getState();
    791         boolean hasRingingCall = hasActiveRingingCall();
    792         boolean hasActiveCall = hasActiveFgCall();
    793         boolean hasHoldingCall = hasActiveBgCall();
    794         boolean allLinesTaken = hasActiveCall && hasHoldingCall;
    795         Call.State fgCallState = getActiveFgCallState();
    796 
    797         boolean result = (serviceState != ServiceState.STATE_POWER_OFF
    798                 && !hasRingingCall
    799                 && !allLinesTaken
    800                 && ((fgCallState == Call.State.ACTIVE)
    801                     || (fgCallState == Call.State.IDLE)
    802                     || (fgCallState == Call.State.DISCONNECTED)));
    803 
    804         if (result == false) {
    805             Log.d(LOG_TAG, "canDial serviceState=" + serviceState
    806                             + " hasRingingCall=" + hasRingingCall
    807                             + " hasActiveCall=" + hasActiveCall
    808                             + " hasHoldingCall=" + hasHoldingCall
    809                             + " allLinesTaken=" + allLinesTaken
    810                             + " fgCallState=" + fgCallState);
    811         }
    812         return result;
    813     }
    814 
    815     /**
    816      * Whether or not the phone can do explicit call transfer in the current
    817      * phone state--that is, one call holding and one call active.
    818      * @return true if the phone can do explicit call transfer; false otherwise.
    819      */
    820     public boolean canTransfer(Call heldCall) {
    821         Phone activePhone = null;
    822         Phone heldPhone = null;
    823 
    824         if (hasActiveFgCall()) {
    825             activePhone = getActiveFgCall().getPhone();
    826         }
    827 
    828         if (heldCall != null) {
    829             heldPhone = heldCall.getPhone();
    830         }
    831 
    832         return (heldPhone == activePhone && activePhone.canTransfer());
    833     }
    834 
    835     /**
    836      * Connects the held call and active call
    837      * Disconnects the subscriber from both calls
    838      *
    839      * Explicit Call Transfer occurs asynchronously
    840      * and may fail. Final notification occurs via
    841      * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
    842      * java.lang.Object) registerForPreciseCallStateChanged()}.
    843      *
    844      * @exception CallStateException if canTransfer() would return false.
    845      * In these cases, this operation may not be performed.
    846      */
    847     public void explicitCallTransfer(Call heldCall) throws CallStateException {
    848         if (VDBG) {
    849             Log.d(LOG_TAG, " explicitCallTransfer(" + heldCall + ")");
    850             Log.d(LOG_TAG, this.toString());
    851         }
    852 
    853         if (canTransfer(heldCall)) {
    854             heldCall.getPhone().explicitCallTransfer();
    855         }
    856 
    857         if (VDBG) {
    858             Log.d(LOG_TAG, "End explicitCallTransfer(" + heldCall + ")");
    859             Log.d(LOG_TAG, this.toString());
    860         }
    861 
    862     }
    863 
    864     /**
    865      * Returns a list of MMI codes that are pending for a phone. (They have initiated
    866      * but have not yet completed).
    867      * Presently there is only ever one.
    868      *
    869      * Use <code>registerForMmiInitiate</code>
    870      * and <code>registerForMmiComplete</code> for change notification.
    871      * @return null if phone doesn't have or support mmi code
    872      */
    873     public List<? extends MmiCode> getPendingMmiCodes(Phone phone) {
    874         Log.e(LOG_TAG, "getPendingMmiCodes not implemented");
    875         return null;
    876     }
    877 
    878     /**
    879      * Sends user response to a USSD REQUEST message.  An MmiCode instance
    880      * representing this response is sent to handlers registered with
    881      * registerForMmiInitiate.
    882      *
    883      * @param ussdMessge    Message to send in the response.
    884      * @return false if phone doesn't support ussd service
    885      */
    886     public boolean sendUssdResponse(Phone phone, String ussdMessge) {
    887         Log.e(LOG_TAG, "sendUssdResponse not implemented");
    888         return false;
    889     }
    890 
    891     /**
    892      * Mutes or unmutes the microphone for the active call. The microphone
    893      * is automatically unmuted if a call is answered, dialed, or resumed
    894      * from a holding state.
    895      *
    896      * @param muted true to mute the microphone,
    897      * false to activate the microphone.
    898      */
    899 
    900     public void setMute(boolean muted) {
    901         if (VDBG) {
    902             Log.d(LOG_TAG, " setMute(" + muted + ")");
    903             Log.d(LOG_TAG, this.toString());
    904         }
    905 
    906         if (hasActiveFgCall()) {
    907             getActiveFgCall().getPhone().setMute(muted);
    908         }
    909 
    910         if (VDBG) {
    911             Log.d(LOG_TAG, "End setMute(" + muted + ")");
    912             Log.d(LOG_TAG, this.toString());
    913         }
    914     }
    915 
    916     /**
    917      * Gets current mute status. Use
    918      * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
    919      * java.lang.Object) registerForPreciseCallStateChanged()}
    920      * as a change notifcation, although presently phone state changed is not
    921      * fired when setMute() is called.
    922      *
    923      * @return true is muting, false is unmuting
    924      */
    925     public boolean getMute() {
    926         if (hasActiveFgCall()) {
    927             return getActiveFgCall().getPhone().getMute();
    928         } else if (hasActiveBgCall()) {
    929             return getFirstActiveBgCall().getPhone().getMute();
    930         }
    931         return false;
    932     }
    933 
    934     /**
    935      * Enables or disables echo suppression.
    936      */
    937     public void setEchoSuppressionEnabled(boolean enabled) {
    938         if (VDBG) {
    939             Log.d(LOG_TAG, " setEchoSuppression(" + enabled + ")");
    940             Log.d(LOG_TAG, this.toString());
    941         }
    942 
    943         if (hasActiveFgCall()) {
    944             getActiveFgCall().getPhone().setEchoSuppressionEnabled(enabled);
    945         }
    946 
    947         if (VDBG) {
    948             Log.d(LOG_TAG, "End setEchoSuppression(" + enabled + ")");
    949             Log.d(LOG_TAG, this.toString());
    950         }
    951     }
    952 
    953     /**
    954      * Play a DTMF tone on the active call.
    955      *
    956      * @param c should be one of 0-9, '*' or '#'. Other values will be
    957      * silently ignored.
    958      * @return false if no active call or the active call doesn't support
    959      *         dtmf tone
    960      */
    961     public boolean sendDtmf(char c) {
    962         boolean result = false;
    963 
    964         if (VDBG) {
    965             Log.d(LOG_TAG, " sendDtmf(" + c + ")");
    966             Log.d(LOG_TAG, this.toString());
    967         }
    968 
    969         if (hasActiveFgCall()) {
    970             getActiveFgCall().getPhone().sendDtmf(c);
    971             result = true;
    972         }
    973 
    974         if (VDBG) {
    975             Log.d(LOG_TAG, "End sendDtmf(" + c + ")");
    976             Log.d(LOG_TAG, this.toString());
    977         }
    978         return result;
    979     }
    980 
    981     /**
    982      * Start to paly a DTMF tone on the active call.
    983      * or there is a playing DTMF tone.
    984      * @param c should be one of 0-9, '*' or '#'. Other values will be
    985      * silently ignored.
    986      *
    987      * @return false if no active call or the active call doesn't support
    988      *         dtmf tone
    989      */
    990     public boolean startDtmf(char c) {
    991         boolean result = false;
    992 
    993         if (VDBG) {
    994             Log.d(LOG_TAG, " startDtmf(" + c + ")");
    995             Log.d(LOG_TAG, this.toString());
    996         }
    997 
    998         if (hasActiveFgCall()) {
    999             getActiveFgCall().getPhone().startDtmf(c);
   1000             result = true;
   1001         }
   1002 
   1003         if (VDBG) {
   1004             Log.d(LOG_TAG, "End startDtmf(" + c + ")");
   1005             Log.d(LOG_TAG, this.toString());
   1006         }
   1007 
   1008         return result;
   1009     }
   1010 
   1011     /**
   1012      * Stop the playing DTMF tone. Ignored if there is no playing DTMF
   1013      * tone or no active call.
   1014      */
   1015     public void stopDtmf() {
   1016         if (VDBG) {
   1017             Log.d(LOG_TAG, " stopDtmf()" );
   1018             Log.d(LOG_TAG, this.toString());
   1019         }
   1020 
   1021         if (hasActiveFgCall()) getFgPhone().stopDtmf();
   1022 
   1023         if (VDBG) {
   1024             Log.d(LOG_TAG, "End stopDtmf()");
   1025             Log.d(LOG_TAG, this.toString());
   1026         }
   1027     }
   1028 
   1029     /**
   1030      * send burst DTMF tone, it can send the string as single character or multiple character
   1031      * ignore if there is no active call or not valid digits string.
   1032      * Valid digit means only includes characters ISO-LATIN characters 0-9, *, #
   1033      * The difference between sendDtmf and sendBurstDtmf is sendDtmf only sends one character,
   1034      * this api can send single character and multiple character, also, this api has response
   1035      * back to caller.
   1036      *
   1037      * @param dtmfString is string representing the dialing digit(s) in the active call
   1038      * @param on the DTMF ON length in milliseconds, or 0 for default
   1039      * @param off the DTMF OFF length in milliseconds, or 0 for default
   1040      * @param onComplete is the callback message when the action is processed by BP
   1041      *
   1042      */
   1043     public boolean sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
   1044         if (hasActiveFgCall()) {
   1045             getActiveFgCall().getPhone().sendBurstDtmf(dtmfString, on, off, onComplete);
   1046             return true;
   1047         }
   1048         return false;
   1049     }
   1050 
   1051     /**
   1052      * Notifies when a voice connection has disconnected, either due to local
   1053      * or remote hangup or error.
   1054      *
   1055      *  Messages received from this will have the following members:<p>
   1056      *  <ul><li>Message.obj will be an AsyncResult</li>
   1057      *  <li>AsyncResult.userObj = obj</li>
   1058      *  <li>AsyncResult.result = a Connection object that is
   1059      *  no longer connected.</li></ul>
   1060      */
   1061     public void registerForDisconnect(Handler h, int what, Object obj) {
   1062         mDisconnectRegistrants.addUnique(h, what, obj);
   1063     }
   1064 
   1065     /**
   1066      * Unregisters for voice disconnection notification.
   1067      * Extraneous calls are tolerated silently
   1068      */
   1069     public void unregisterForDisconnect(Handler h){
   1070         mDisconnectRegistrants.remove(h);
   1071     }
   1072 
   1073     /**
   1074      * Register for getting notifications for change in the Call State {@link Call.State}
   1075      * This is called PreciseCallState because the call state is more precise than the
   1076      * {@link Phone.State} which can be obtained using the {@link PhoneStateListener}
   1077      *
   1078      * Resulting events will have an AsyncResult in <code>Message.obj</code>.
   1079      * AsyncResult.userData will be set to the obj argument here.
   1080      * The <em>h</em> parameter is held only by a weak reference.
   1081      */
   1082     public void registerForPreciseCallStateChanged(Handler h, int what, Object obj){
   1083         mPreciseCallStateRegistrants.addUnique(h, what, obj);
   1084     }
   1085 
   1086     /**
   1087      * Unregisters for voice call state change notifications.
   1088      * Extraneous calls are tolerated silently.
   1089      */
   1090     public void unregisterForPreciseCallStateChanged(Handler h){
   1091         mPreciseCallStateRegistrants.remove(h);
   1092     }
   1093 
   1094     /**
   1095      * Notifies when a previously untracked non-ringing/waiting connection has appeared.
   1096      * This is likely due to some other entity (eg, SIM card application) initiating a call.
   1097      */
   1098     public void registerForUnknownConnection(Handler h, int what, Object obj){
   1099         mUnknownConnectionRegistrants.addUnique(h, what, obj);
   1100     }
   1101 
   1102     /**
   1103      * Unregisters for unknown connection notifications.
   1104      */
   1105     public void unregisterForUnknownConnection(Handler h){
   1106         mUnknownConnectionRegistrants.remove(h);
   1107     }
   1108 
   1109 
   1110     /**
   1111      * Notifies when a new ringing or waiting connection has appeared.<p>
   1112      *
   1113      *  Messages received from this:
   1114      *  Message.obj will be an AsyncResult
   1115      *  AsyncResult.userObj = obj
   1116      *  AsyncResult.result = a Connection. <p>
   1117      *  Please check Connection.isRinging() to make sure the Connection
   1118      *  has not dropped since this message was posted.
   1119      *  If Connection.isRinging() is true, then
   1120      *   Connection.getCall() == Phone.getRingingCall()
   1121      */
   1122     public void registerForNewRingingConnection(Handler h, int what, Object obj){
   1123         mNewRingingConnectionRegistrants.addUnique(h, what, obj);
   1124     }
   1125 
   1126     /**
   1127      * Unregisters for new ringing connection notification.
   1128      * Extraneous calls are tolerated silently
   1129      */
   1130 
   1131     public void unregisterForNewRingingConnection(Handler h){
   1132         mNewRingingConnectionRegistrants.remove(h);
   1133     }
   1134 
   1135     /**
   1136      * Notifies when an incoming call rings.<p>
   1137      *
   1138      *  Messages received from this:
   1139      *  Message.obj will be an AsyncResult
   1140      *  AsyncResult.userObj = obj
   1141      *  AsyncResult.result = a Connection. <p>
   1142      */
   1143     public void registerForIncomingRing(Handler h, int what, Object obj){
   1144         mIncomingRingRegistrants.addUnique(h, what, obj);
   1145     }
   1146 
   1147     /**
   1148      * Unregisters for ring notification.
   1149      * Extraneous calls are tolerated silently
   1150      */
   1151 
   1152     public void unregisterForIncomingRing(Handler h){
   1153         mIncomingRingRegistrants.remove(h);
   1154     }
   1155 
   1156     /**
   1157      * Notifies when out-band ringback tone is needed.<p>
   1158      *
   1159      *  Messages received from this:
   1160      *  Message.obj will be an AsyncResult
   1161      *  AsyncResult.userObj = obj
   1162      *  AsyncResult.result = boolean, true to start play ringback tone
   1163      *                       and false to stop. <p>
   1164      */
   1165     public void registerForRingbackTone(Handler h, int what, Object obj){
   1166         mRingbackToneRegistrants.addUnique(h, what, obj);
   1167     }
   1168 
   1169     /**
   1170      * Unregisters for ringback tone notification.
   1171      */
   1172 
   1173     public void unregisterForRingbackTone(Handler h){
   1174         mRingbackToneRegistrants.remove(h);
   1175     }
   1176 
   1177     /**
   1178      * Registers the handler to reset the uplink mute state to get
   1179      * uplink audio.
   1180      */
   1181     public void registerForResendIncallMute(Handler h, int what, Object obj){
   1182         mResendIncallMuteRegistrants.addUnique(h, what, obj);
   1183     }
   1184 
   1185     /**
   1186      * Unregisters for resend incall mute notifications.
   1187      */
   1188     public void unregisterForResendIncallMute(Handler h){
   1189         mResendIncallMuteRegistrants.remove(h);
   1190     }
   1191 
   1192     /**
   1193      * Register for notifications of initiation of a new MMI code request.
   1194      * MMI codes for GSM are discussed in 3GPP TS 22.030.<p>
   1195      *
   1196      * Example: If Phone.dial is called with "*#31#", then the app will
   1197      * be notified here.<p>
   1198      *
   1199      * The returned <code>Message.obj</code> will contain an AsyncResult.
   1200      *
   1201      * <code>obj.result</code> will be an "MmiCode" object.
   1202      */
   1203     public void registerForMmiInitiate(Handler h, int what, Object obj){
   1204         mMmiInitiateRegistrants.addUnique(h, what, obj);
   1205     }
   1206 
   1207     /**
   1208      * Unregisters for new MMI initiate notification.
   1209      * Extraneous calls are tolerated silently
   1210      */
   1211     public void unregisterForMmiInitiate(Handler h){
   1212         mMmiInitiateRegistrants.remove(h);
   1213     }
   1214 
   1215     /**
   1216      * Register for notifications that an MMI request has completed
   1217      * its network activity and is in its final state. This may mean a state
   1218      * of COMPLETE, FAILED, or CANCELLED.
   1219      *
   1220      * <code>Message.obj</code> will contain an AsyncResult.
   1221      * <code>obj.result</code> will be an "MmiCode" object
   1222      */
   1223     public void registerForMmiComplete(Handler h, int what, Object obj){
   1224         mMmiCompleteRegistrants.addUnique(h, what, obj);
   1225     }
   1226 
   1227     /**
   1228      * Unregisters for MMI complete notification.
   1229      * Extraneous calls are tolerated silently
   1230      */
   1231     public void unregisterForMmiComplete(Handler h){
   1232         mMmiCompleteRegistrants.remove(h);
   1233     }
   1234 
   1235     /**
   1236      * Registration point for Ecm timer reset
   1237      * @param h handler to notify
   1238      * @param what user-defined message code
   1239      * @param obj placed in Message.obj
   1240      */
   1241     public void registerForEcmTimerReset(Handler h, int what, Object obj){
   1242         mEcmTimerResetRegistrants.addUnique(h, what, obj);
   1243     }
   1244 
   1245     /**
   1246      * Unregister for notification for Ecm timer reset
   1247      * @param h Handler to be removed from the registrant list.
   1248      */
   1249     public void unregisterForEcmTimerReset(Handler h){
   1250         mEcmTimerResetRegistrants.remove(h);
   1251     }
   1252 
   1253     /**
   1254      * Register for ServiceState changed.
   1255      * Message.obj will contain an AsyncResult.
   1256      * AsyncResult.result will be a ServiceState instance
   1257      */
   1258     public void registerForServiceStateChanged(Handler h, int what, Object obj){
   1259         mServiceStateChangedRegistrants.addUnique(h, what, obj);
   1260     }
   1261 
   1262     /**
   1263      * Unregisters for ServiceStateChange notification.
   1264      * Extraneous calls are tolerated silently
   1265      */
   1266     public void unregisterForServiceStateChanged(Handler h){
   1267         mServiceStateChangedRegistrants.remove(h);
   1268     }
   1269 
   1270     /**
   1271      * Register for notifications when a supplementary service attempt fails.
   1272      * Message.obj will contain an AsyncResult.
   1273      *
   1274      * @param h Handler that receives the notification message.
   1275      * @param what User-defined message code.
   1276      * @param obj User object.
   1277      */
   1278     public void registerForSuppServiceFailed(Handler h, int what, Object obj){
   1279         mSuppServiceFailedRegistrants.addUnique(h, what, obj);
   1280     }
   1281 
   1282     /**
   1283      * Unregister for notifications when a supplementary service attempt fails.
   1284      * Extraneous calls are tolerated silently
   1285      *
   1286      * @param h Handler to be removed from the registrant list.
   1287      */
   1288     public void unregisterForSuppServiceFailed(Handler h){
   1289         mSuppServiceFailedRegistrants.remove(h);
   1290     }
   1291 
   1292     /**
   1293      * Register for notifications when a sInCall VoicePrivacy is enabled
   1294      *
   1295      * @param h Handler that receives the notification message.
   1296      * @param what User-defined message code.
   1297      * @param obj User object.
   1298      */
   1299     public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
   1300         mInCallVoicePrivacyOnRegistrants.addUnique(h, what, obj);
   1301     }
   1302 
   1303     /**
   1304      * Unregister for notifications when a sInCall VoicePrivacy is enabled
   1305      *
   1306      * @param h Handler to be removed from the registrant list.
   1307      */
   1308     public void unregisterForInCallVoicePrivacyOn(Handler h){
   1309         mInCallVoicePrivacyOnRegistrants.remove(h);
   1310     }
   1311 
   1312     /**
   1313      * Register for notifications when a sInCall VoicePrivacy is disabled
   1314      *
   1315      * @param h Handler that receives the notification message.
   1316      * @param what User-defined message code.
   1317      * @param obj User object.
   1318      */
   1319     public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
   1320         mInCallVoicePrivacyOffRegistrants.addUnique(h, what, obj);
   1321     }
   1322 
   1323     /**
   1324      * Unregister for notifications when a sInCall VoicePrivacy is disabled
   1325      *
   1326      * @param h Handler to be removed from the registrant list.
   1327      */
   1328     public void unregisterForInCallVoicePrivacyOff(Handler h){
   1329         mInCallVoicePrivacyOffRegistrants.remove(h);
   1330     }
   1331 
   1332     /**
   1333      * Register for notifications when CDMA call waiting comes
   1334      *
   1335      * @param h Handler that receives the notification message.
   1336      * @param what User-defined message code.
   1337      * @param obj User object.
   1338      */
   1339     public void registerForCallWaiting(Handler h, int what, Object obj){
   1340         mCallWaitingRegistrants.addUnique(h, what, obj);
   1341     }
   1342 
   1343     /**
   1344      * Unregister for notifications when CDMA Call waiting comes
   1345      * @param h Handler to be removed from the registrant list.
   1346      */
   1347     public void unregisterForCallWaiting(Handler h){
   1348         mCallWaitingRegistrants.remove(h);
   1349     }
   1350 
   1351 
   1352     /**
   1353      * Register for signal information notifications from the network.
   1354      * Message.obj will contain an AsyncResult.
   1355      * AsyncResult.result will be a SuppServiceNotification instance.
   1356      *
   1357      * @param h Handler that receives the notification message.
   1358      * @param what User-defined message code.
   1359      * @param obj User object.
   1360      */
   1361 
   1362     public void registerForSignalInfo(Handler h, int what, Object obj){
   1363         mSignalInfoRegistrants.addUnique(h, what, obj);
   1364     }
   1365 
   1366     /**
   1367      * Unregisters for signal information notifications.
   1368      * Extraneous calls are tolerated silently
   1369      *
   1370      * @param h Handler to be removed from the registrant list.
   1371      */
   1372     public void unregisterForSignalInfo(Handler h){
   1373         mSignalInfoRegistrants.remove(h);
   1374     }
   1375 
   1376     /**
   1377      * Register for display information notifications from the network.
   1378      * Message.obj will contain an AsyncResult.
   1379      * AsyncResult.result will be a SuppServiceNotification instance.
   1380      *
   1381      * @param h Handler that receives the notification message.
   1382      * @param what User-defined message code.
   1383      * @param obj User object.
   1384      */
   1385     public void registerForDisplayInfo(Handler h, int what, Object obj){
   1386         mDisplayInfoRegistrants.addUnique(h, what, obj);
   1387     }
   1388 
   1389     /**
   1390      * Unregisters for display information notifications.
   1391      * Extraneous calls are tolerated silently
   1392      *
   1393      * @param h Handler to be removed from the registrant list.
   1394      */
   1395     public void unregisterForDisplayInfo(Handler h) {
   1396         mDisplayInfoRegistrants.remove(h);
   1397     }
   1398 
   1399     /**
   1400      * Register for notifications when CDMA OTA Provision status change
   1401      *
   1402      * @param h Handler that receives the notification message.
   1403      * @param what User-defined message code.
   1404      * @param obj User object.
   1405      */
   1406     public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj){
   1407         mCdmaOtaStatusChangeRegistrants.addUnique(h, what, obj);
   1408     }
   1409 
   1410     /**
   1411      * Unregister for notifications when CDMA OTA Provision status change
   1412      * @param h Handler to be removed from the registrant list.
   1413      */
   1414     public void unregisterForCdmaOtaStatusChange(Handler h){
   1415         mCdmaOtaStatusChangeRegistrants.remove(h);
   1416     }
   1417 
   1418     /**
   1419      * Registration point for subscription info ready
   1420      * @param h handler to notify
   1421      * @param what what code of message when delivered
   1422      * @param obj placed in Message.obj
   1423      */
   1424     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj){
   1425         mSubscriptionInfoReadyRegistrants.addUnique(h, what, obj);
   1426     }
   1427 
   1428     /**
   1429      * Unregister for notifications for subscription info
   1430      * @param h Handler to be removed from the registrant list.
   1431      */
   1432     public void unregisterForSubscriptionInfoReady(Handler h){
   1433         mSubscriptionInfoReadyRegistrants.remove(h);
   1434     }
   1435 
   1436     /**
   1437      * Sets an event to be fired when the telephony system processes
   1438      * a post-dial character on an outgoing call.<p>
   1439      *
   1440      * Messages of type <code>what</code> will be sent to <code>h</code>.
   1441      * The <code>obj</code> field of these Message's will be instances of
   1442      * <code>AsyncResult</code>. <code>Message.obj.result</code> will be
   1443      * a Connection object.<p>
   1444      *
   1445      * Message.arg1 will be the post dial character being processed,
   1446      * or 0 ('\0') if end of string.<p>
   1447      *
   1448      * If Connection.getPostDialState() == WAIT,
   1449      * the application must call
   1450      * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar()
   1451      * Connection.proceedAfterWaitChar()} or
   1452      * {@link com.android.internal.telephony.Connection#cancelPostDial()
   1453      * Connection.cancelPostDial()}
   1454      * for the telephony system to continue playing the post-dial
   1455      * DTMF sequence.<p>
   1456      *
   1457      * If Connection.getPostDialState() == WILD,
   1458      * the application must call
   1459      * {@link com.android.internal.telephony.Connection#proceedAfterWildChar
   1460      * Connection.proceedAfterWildChar()}
   1461      * or
   1462      * {@link com.android.internal.telephony.Connection#cancelPostDial()
   1463      * Connection.cancelPostDial()}
   1464      * for the telephony system to continue playing the
   1465      * post-dial DTMF sequence.<p>
   1466      *
   1467      */
   1468     public void registerForPostDialCharacter(Handler h, int what, Object obj){
   1469         mPostDialCharacterRegistrants.addUnique(h, what, obj);
   1470     }
   1471 
   1472     public void unregisterForPostDialCharacter(Handler h){
   1473         mPostDialCharacterRegistrants.remove(h);
   1474     }
   1475 
   1476     /* APIs to access foregroudCalls, backgroudCalls, and ringingCalls
   1477      * 1. APIs to access list of calls
   1478      * 2. APIs to check if any active call, which has connection other than
   1479      * disconnected ones, pleaser refer to Call.isIdle()
   1480      * 3. APIs to return first active call
   1481      * 4. APIs to return the connections of first active call
   1482      * 5. APIs to return other property of first active call
   1483      */
   1484 
   1485     /**
   1486      * @return list of all ringing calls
   1487      */
   1488     public List<Call> getRingingCalls() {
   1489         return Collections.unmodifiableList(mRingingCalls);
   1490     }
   1491 
   1492     /**
   1493      * @return list of all foreground calls
   1494      */
   1495     public List<Call> getForegroundCalls() {
   1496         return Collections.unmodifiableList(mForegroundCalls);
   1497     }
   1498 
   1499     /**
   1500      * @return list of all background calls
   1501      */
   1502     public List<Call> getBackgroundCalls() {
   1503         return Collections.unmodifiableList(mBackgroundCalls);
   1504     }
   1505 
   1506     /**
   1507      * Return true if there is at least one active foreground call
   1508      */
   1509     public boolean hasActiveFgCall() {
   1510         return (getFirstActiveCall(mForegroundCalls) != null);
   1511     }
   1512 
   1513     /**
   1514      * Return true if there is at least one active background call
   1515      */
   1516     public boolean hasActiveBgCall() {
   1517         // TODO since hasActiveBgCall may get called often
   1518         // better to cache it to improve performance
   1519         return (getFirstActiveCall(mBackgroundCalls) != null);
   1520     }
   1521 
   1522     /**
   1523      * Return true if there is at least one active ringing call
   1524      *
   1525      */
   1526     public boolean hasActiveRingingCall() {
   1527         return (getFirstActiveCall(mRingingCalls) != null);
   1528     }
   1529 
   1530     /**
   1531      * return the active foreground call from foreground calls
   1532      *
   1533      * Active call means the call is NOT in Call.State.IDLE
   1534      *
   1535      * 1. If there is active foreground call, return it
   1536      * 2. If there is no active foreground call, return the
   1537      *    foreground call associated with default phone, which state is IDLE.
   1538      * 3. If there is no phone registered at all, return null.
   1539      *
   1540      */
   1541     public Call getActiveFgCall() {
   1542         Call call = getFirstNonIdleCall(mForegroundCalls);
   1543         if (call == null) {
   1544             call = (mDefaultPhone == null)
   1545                     ? null
   1546                     : mDefaultPhone.getForegroundCall();
   1547         }
   1548         return call;
   1549     }
   1550 
   1551     // Returns the first call that is not in IDLE state. If both active calls
   1552     // and disconnecting/disconnected calls exist, return the first active call.
   1553     private Call getFirstNonIdleCall(List<Call> calls) {
   1554         Call result = null;
   1555         for (Call call : calls) {
   1556             if (!call.isIdle()) {
   1557                 return call;
   1558             } else if (call.getState() != Call.State.IDLE) {
   1559                 if (result == null) result = call;
   1560             }
   1561         }
   1562         return result;
   1563     }
   1564 
   1565     /**
   1566      * return one active background call from background calls
   1567      *
   1568      * Active call means the call is NOT idle defined by Call.isIdle()
   1569      *
   1570      * 1. If there is only one active background call, return it
   1571      * 2. If there is more than one active background call, return the first one
   1572      * 3. If there is no active background call, return the background call
   1573      *    associated with default phone, which state is IDLE.
   1574      * 4. If there is no background call at all, return null.
   1575      *
   1576      * Complete background calls list can be get by getBackgroundCalls()
   1577      */
   1578     public Call getFirstActiveBgCall() {
   1579         Call call = getFirstNonIdleCall(mBackgroundCalls);
   1580         if (call == null) {
   1581             call = (mDefaultPhone == null)
   1582                     ? null
   1583                     : mDefaultPhone.getBackgroundCall();
   1584         }
   1585         return call;
   1586     }
   1587 
   1588     /**
   1589      * return one active ringing call from ringing calls
   1590      *
   1591      * Active call means the call is NOT idle defined by Call.isIdle()
   1592      *
   1593      * 1. If there is only one active ringing call, return it
   1594      * 2. If there is more than one active ringing call, return the first one
   1595      * 3. If there is no active ringing call, return the ringing call
   1596      *    associated with default phone, which state is IDLE.
   1597      * 4. If there is no ringing call at all, return null.
   1598      *
   1599      * Complete ringing calls list can be get by getRingingCalls()
   1600      */
   1601     public Call getFirstActiveRingingCall() {
   1602         Call call = getFirstNonIdleCall(mRingingCalls);
   1603         if (call == null) {
   1604             call = (mDefaultPhone == null)
   1605                     ? null
   1606                     : mDefaultPhone.getRingingCall();
   1607         }
   1608         return call;
   1609     }
   1610 
   1611     /**
   1612      * @return the state of active foreground call
   1613      * return IDLE if there is no active foreground call
   1614      */
   1615     public Call.State getActiveFgCallState() {
   1616         Call fgCall = getActiveFgCall();
   1617 
   1618         if (fgCall != null) {
   1619             return fgCall.getState();
   1620         }
   1621 
   1622         return Call.State.IDLE;
   1623     }
   1624 
   1625     /**
   1626      * @return the connections of active foreground call
   1627      * return empty list if there is no active foreground call
   1628      */
   1629     public List<Connection> getFgCallConnections() {
   1630         Call fgCall = getActiveFgCall();
   1631         if ( fgCall != null) {
   1632             return fgCall.getConnections();
   1633         }
   1634         return emptyConnections;
   1635     }
   1636 
   1637     /**
   1638      * @return the connections of active background call
   1639      * return empty list if there is no active background call
   1640      */
   1641     public List<Connection> getBgCallConnections() {
   1642         Call bgCall = getFirstActiveBgCall();
   1643         if ( bgCall != null) {
   1644             return bgCall.getConnections();
   1645         }
   1646         return emptyConnections;
   1647     }
   1648 
   1649     /**
   1650      * @return the latest connection of active foreground call
   1651      * return null if there is no active foreground call
   1652      */
   1653     public Connection getFgCallLatestConnection() {
   1654         Call fgCall = getActiveFgCall();
   1655         if ( fgCall != null) {
   1656             return fgCall.getLatestConnection();
   1657         }
   1658         return null;
   1659     }
   1660 
   1661     /**
   1662      * @return true if there is at least one Foreground call in disconnected state
   1663      */
   1664     public boolean hasDisconnectedFgCall() {
   1665         return (getFirstCallOfState(mForegroundCalls, Call.State.DISCONNECTED) != null);
   1666     }
   1667 
   1668     /**
   1669      * @return true if there is at least one background call in disconnected state
   1670      */
   1671     public boolean hasDisconnectedBgCall() {
   1672         return (getFirstCallOfState(mBackgroundCalls, Call.State.DISCONNECTED) != null);
   1673     }
   1674 
   1675     /**
   1676      * @return the first active call from a call list
   1677      */
   1678     private  Call getFirstActiveCall(ArrayList<Call> calls) {
   1679         for (Call call : calls) {
   1680             if (!call.isIdle()) {
   1681                 return call;
   1682             }
   1683         }
   1684         return null;
   1685     }
   1686 
   1687     /**
   1688      * @return the first call in a the Call.state from a call list
   1689      */
   1690     private Call getFirstCallOfState(ArrayList<Call> calls, Call.State state) {
   1691         for (Call call : calls) {
   1692             if (call.getState() == state) {
   1693                 return call;
   1694             }
   1695         }
   1696         return null;
   1697     }
   1698 
   1699 
   1700     private boolean hasMoreThanOneRingingCall() {
   1701         int count = 0;
   1702         for (Call call : mRingingCalls) {
   1703             if (call.getState().isRinging()) {
   1704                 if (++count > 1) return true;
   1705             }
   1706         }
   1707         return false;
   1708     }
   1709 
   1710     private Handler mHandler = new Handler() {
   1711 
   1712         @Override
   1713         public void handleMessage(Message msg) {
   1714 
   1715             switch (msg.what) {
   1716                 case EVENT_DISCONNECT:
   1717                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_DISCONNECT)");
   1718                     mDisconnectRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1719                     break;
   1720                 case EVENT_PRECISE_CALL_STATE_CHANGED:
   1721                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_PRECISE_CALL_STATE_CHANGED)");
   1722                     mPreciseCallStateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1723                     break;
   1724                 case EVENT_NEW_RINGING_CONNECTION:
   1725                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_NEW_RINGING_CONNECTION)");
   1726                     if (getActiveFgCallState().isDialing() || hasMoreThanOneRingingCall()) {
   1727                         Connection c = (Connection) ((AsyncResult) msg.obj).result;
   1728                         try {
   1729                             Log.d(LOG_TAG, "silently drop incoming call: " + c.getCall());
   1730                             c.getCall().hangup();
   1731                         } catch (CallStateException e) {
   1732                             Log.w(LOG_TAG, "new ringing connection", e);
   1733                         }
   1734                     } else {
   1735                         mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1736                     }
   1737                     break;
   1738                 case EVENT_UNKNOWN_CONNECTION:
   1739                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_UNKNOWN_CONNECTION)");
   1740                     mUnknownConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1741                     break;
   1742                 case EVENT_INCOMING_RING:
   1743                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_INCOMING_RING)");
   1744                     // The event may come from RIL who's not aware of an ongoing fg call
   1745                     if (!hasActiveFgCall()) {
   1746                         mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1747                     }
   1748                     break;
   1749                 case EVENT_RINGBACK_TONE:
   1750                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_RINGBACK_TONE)");
   1751                     mRingbackToneRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1752                     break;
   1753                 case EVENT_IN_CALL_VOICE_PRIVACY_ON:
   1754                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_ON)");
   1755                     mInCallVoicePrivacyOnRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1756                     break;
   1757                 case EVENT_IN_CALL_VOICE_PRIVACY_OFF:
   1758                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_OFF)");
   1759                     mInCallVoicePrivacyOffRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1760                     break;
   1761                 case EVENT_CALL_WAITING:
   1762                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_CALL_WAITING)");
   1763                     mCallWaitingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1764                     break;
   1765                 case EVENT_DISPLAY_INFO:
   1766                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_DISPLAY_INFO)");
   1767                     mDisplayInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1768                     break;
   1769                 case EVENT_SIGNAL_INFO:
   1770                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SIGNAL_INFO)");
   1771                     mSignalInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1772                     break;
   1773                 case EVENT_CDMA_OTA_STATUS_CHANGE:
   1774                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_CDMA_OTA_STATUS_CHANGE)");
   1775                     mCdmaOtaStatusChangeRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1776                     break;
   1777                 case EVENT_RESEND_INCALL_MUTE:
   1778                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_RESEND_INCALL_MUTE)");
   1779                     mResendIncallMuteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1780                     break;
   1781                 case EVENT_MMI_INITIATE:
   1782                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_MMI_INITIATE)");
   1783                     mMmiInitiateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1784                     break;
   1785                 case EVENT_MMI_COMPLETE:
   1786                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_MMI_COMPLETE)");
   1787                     mMmiCompleteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1788                     break;
   1789                 case EVENT_ECM_TIMER_RESET:
   1790                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_ECM_TIMER_RESET)");
   1791                     mEcmTimerResetRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1792                     break;
   1793                 case EVENT_SUBSCRIPTION_INFO_READY:
   1794                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SUBSCRIPTION_INFO_READY)");
   1795                     mSubscriptionInfoReadyRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1796                     break;
   1797                 case EVENT_SUPP_SERVICE_FAILED:
   1798                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SUPP_SERVICE_FAILED)");
   1799                     mSuppServiceFailedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1800                     break;
   1801                 case EVENT_SERVICE_STATE_CHANGED:
   1802                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SERVICE_STATE_CHANGED)");
   1803                     mServiceStateChangedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
   1804                     break;
   1805                 case EVENT_POST_DIAL_CHARACTER:
   1806                     // we need send the character that is being processed in msg.arg1
   1807                     // so can't use notifyRegistrants()
   1808                     if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_POST_DIAL_CHARACTER)");
   1809                     for(int i=0; i < mPostDialCharacterRegistrants.size(); i++) {
   1810                         Message notifyMsg;
   1811                         notifyMsg = ((Registrant)mPostDialCharacterRegistrants.get(i)).messageForRegistrant();
   1812                         notifyMsg.obj = msg.obj;
   1813                         notifyMsg.arg1 = msg.arg1;
   1814                         notifyMsg.sendToTarget();
   1815                     }
   1816                     break;
   1817             }
   1818         }
   1819     };
   1820 
   1821     @Override
   1822     public String toString() {
   1823         Call call;
   1824         StringBuilder b = new StringBuilder();
   1825 
   1826         b.append("CallManager {");
   1827         b.append("\nstate = " + getState());
   1828         call = getActiveFgCall();
   1829         b.append("\n- Foreground: " + getActiveFgCallState());
   1830         b.append(" from " + call.getPhone());
   1831         b.append("\n  Conn: ").append(getFgCallConnections());
   1832         call = getFirstActiveBgCall();
   1833         b.append("\n- Background: " + call.getState());
   1834         b.append(" from " + call.getPhone());
   1835         b.append("\n  Conn: ").append(getBgCallConnections());
   1836         call = getFirstActiveRingingCall();
   1837         b.append("\n- Ringing: " +call.getState());
   1838         b.append(" from " + call.getPhone());
   1839 
   1840         for (Phone phone : getAllPhones()) {
   1841             if (phone != null) {
   1842                 b.append("\nPhone: " + phone + ", name = " + phone.getPhoneName()
   1843                         + ", state = " + phone.getState());
   1844                 call = phone.getForegroundCall();
   1845                 b.append("\n- Foreground: ").append(call);
   1846                 call = phone.getBackgroundCall();
   1847                 b.append(" Background: ").append(call);
   1848                 call = phone.getRingingCall();
   1849                 b.append(" Ringing: ").append(call);
   1850             }
   1851         }
   1852         b.append("\n}");
   1853         return b.toString();
   1854     }
   1855 }
   1856