FileDocCategorySizeDatePackage
CallManager.javaAPI DocAndroid 5.1 API89331Thu Mar 12 22:22:54 GMT 2015com.android.internal.telephony

CallManager

public final class CallManager extends Object
hide
CallManager class provides an abstract layer for PhoneApp to access and control calls. It implements Phone interface. CallManager provides call and connection control as well as channel capability. There are three categories of APIs CallManager provided 1. Call control and operation, such as dial() and hangup() 2. Channel capabilities, such as CanConference() 3. Register notification

Fields Summary
private static final String
LOG_TAG
private static final boolean
DBG
private static final boolean
VDBG
private static final int
EVENT_DISCONNECT
private static final int
EVENT_PRECISE_CALL_STATE_CHANGED
private static final int
EVENT_NEW_RINGING_CONNECTION
private static final int
EVENT_UNKNOWN_CONNECTION
private static final int
EVENT_INCOMING_RING
private static final int
EVENT_RINGBACK_TONE
private static final int
EVENT_IN_CALL_VOICE_PRIVACY_ON
private static final int
EVENT_IN_CALL_VOICE_PRIVACY_OFF
private static final int
EVENT_CALL_WAITING
private static final int
EVENT_DISPLAY_INFO
private static final int
EVENT_SIGNAL_INFO
private static final int
EVENT_CDMA_OTA_STATUS_CHANGE
private static final int
EVENT_RESEND_INCALL_MUTE
private static final int
EVENT_MMI_INITIATE
private static final int
EVENT_MMI_COMPLETE
private static final int
EVENT_ECM_TIMER_RESET
private static final int
EVENT_SUBSCRIPTION_INFO_READY
private static final int
EVENT_SUPP_SERVICE_FAILED
private static final int
EVENT_SERVICE_STATE_CHANGED
private static final int
EVENT_POST_DIAL_CHARACTER
private static final int
EVENT_ONHOLD_TONE
private static final int
EVENT_TTY_MODE_RECEIVED
private static final CallManager
INSTANCE
private final ArrayList
mPhones
private final ArrayList
mRingingCalls
private final ArrayList
mBackgroundCalls
private final ArrayList
mForegroundCalls
private final ArrayList
mEmptyConnections
private final HashMap
mHandlerMap
private Phone
mDefaultPhone
private boolean
mSpeedUpAudioForMtCall
protected final android.os.RegistrantList
mPreciseCallStateRegistrants
protected final android.os.RegistrantList
mNewRingingConnectionRegistrants
protected final android.os.RegistrantList
mIncomingRingRegistrants
protected final android.os.RegistrantList
mDisconnectRegistrants
protected final android.os.RegistrantList
mMmiRegistrants
protected final android.os.RegistrantList
mUnknownConnectionRegistrants
protected final android.os.RegistrantList
mRingbackToneRegistrants
protected final android.os.RegistrantList
mOnHoldToneRegistrants
protected final android.os.RegistrantList
mInCallVoicePrivacyOnRegistrants
protected final android.os.RegistrantList
mInCallVoicePrivacyOffRegistrants
protected final android.os.RegistrantList
mCallWaitingRegistrants
protected final android.os.RegistrantList
mDisplayInfoRegistrants
protected final android.os.RegistrantList
mSignalInfoRegistrants
protected final android.os.RegistrantList
mCdmaOtaStatusChangeRegistrants
protected final android.os.RegistrantList
mResendIncallMuteRegistrants
protected final android.os.RegistrantList
mMmiInitiateRegistrants
protected final android.os.RegistrantList
mMmiCompleteRegistrants
protected final android.os.RegistrantList
mEcmTimerResetRegistrants
protected final android.os.RegistrantList
mSubscriptionInfoReadyRegistrants
protected final android.os.RegistrantList
mSuppServiceFailedRegistrants
protected final android.os.RegistrantList
mServiceStateChangedRegistrants
protected final android.os.RegistrantList
mPostDialCharacterRegistrants
protected final android.os.RegistrantList
mTtyModeReceivedRegistrants
Constructors Summary
private CallManager()


      
        mPhones = new ArrayList<Phone>();
        mRingingCalls = new ArrayList<Call>();
        mBackgroundCalls = new ArrayList<Call>();
        mForegroundCalls = new ArrayList<Call>();
        mDefaultPhone = null;
    
Methods Summary
public voidacceptCall(Call ringingCall)
Answers a ringing or waiting call. Active call, if any, go on hold. If active call can't be held, i.e., a background call of the same channel exists, the active call will be hang up. Answering occurs asynchronously, and final notification occurs via {@link #registerForPreciseCallStateChanged(android.os.Handler, int, java.lang.Object) registerForPreciseCallStateChanged()}.

exception
CallStateException when call is not ringing or waiting

        Phone ringingPhone = ringingCall.getPhone();

        if (VDBG) {
            Rlog.d(LOG_TAG, "acceptCall(" +ringingCall + " from " + ringingCall.getPhone() + ")");
            Rlog.d(LOG_TAG, toString());
        }

        if ( hasActiveFgCall() ) {
            Phone activePhone = getActiveFgCall().getPhone();
            boolean hasBgCall = ! (activePhone.getBackgroundCall().isIdle());
            boolean sameChannel = (activePhone == ringingPhone);

            if (VDBG) {
                Rlog.d(LOG_TAG, "hasBgCall: "+ hasBgCall + "sameChannel:" + sameChannel);
            }

            if (sameChannel && hasBgCall) {
                getActiveFgCall().hangup();
            } else if (!sameChannel && !hasBgCall) {
                activePhone.switchHoldingAndActive();
            } else if (!sameChannel && hasBgCall) {
                getActiveFgCall().hangup();
            }
        }

        // We only support the AUDIO_ONLY video state in this scenario.
        ringingPhone.acceptCall(VideoProfile.VideoState.AUDIO_ONLY);

        if (VDBG) {
            Rlog.d(LOG_TAG, "End acceptCall(" +ringingCall + ")");
            Rlog.d(LOG_TAG, toString());
        }
    
public booleancanConference(Call heldCall)
Whether or not the phone can conference in the current phone state--that is, one call holding and one call active.

return
true if the phone can conference; false otherwise.

        Phone activePhone = null;
        Phone heldPhone = null;

        if (hasActiveFgCall()) {
            activePhone = getActiveFgCall().getPhone();
        }

        if (heldCall != null) {
            heldPhone = heldCall.getPhone();
        }

        return heldPhone.getClass().equals(activePhone.getClass());
    
public booleancanConference(Call heldCall, int subId)
Whether or not the phone can conference in the current phone state--that is, one call holding and one call active. This method consider the phone object which is specific to the provided subId.

return
true if the phone can conference; false otherwise.

        Phone activePhone = null;
        Phone heldPhone = null;

        if (hasActiveFgCall(subId)) {
            activePhone = getActiveFgCall(subId).getPhone();
        }

        if (heldCall != null) {
            heldPhone = heldCall.getPhone();
        }

        return heldPhone.getClass().equals(activePhone.getClass());
    
private booleancanDial(Phone phone)
Phone can make a call only if ALL of the following are true: - Phone is not powered off - There's no incoming or waiting call - The foreground call is ACTIVE or IDLE or DISCONNECTED. (We mainly need to make sure it *isn't* DIALING or ALERTING.)

param
phone
return
true if the phone can make a new call

        int serviceState = phone.getServiceState().getState();
        int subId = phone.getSubId();
        boolean hasRingingCall = hasActiveRingingCall();
        Call.State fgCallState = getActiveFgCallState(subId);

        boolean result = (serviceState != ServiceState.STATE_POWER_OFF
                && !hasRingingCall
                && ((fgCallState == Call.State.ACTIVE)
                    || (fgCallState == Call.State.IDLE)
                    || (fgCallState == Call.State.DISCONNECTED)
                    /*As per 3GPP TS 51.010-1 section 31.13.1.4
                    call should be alowed when the foreground
                    call is in ALERTING state*/
                    || (fgCallState == Call.State.ALERTING)));

        if (result == false) {
            Rlog.d(LOG_TAG, "canDial serviceState=" + serviceState
                            + " hasRingingCall=" + hasRingingCall
                            + " fgCallState=" + fgCallState);
        }
        return result;
    
public booleancanTransfer(Call heldCall)
Whether or not the phone can do explicit call transfer in the current phone state--that is, one call holding and one call active.

return
true if the phone can do explicit call transfer; false otherwise.

        Phone activePhone = null;
        Phone heldPhone = null;

        if (hasActiveFgCall()) {
            activePhone = getActiveFgCall().getPhone();
        }

        if (heldCall != null) {
            heldPhone = heldCall.getPhone();
        }

        return (heldPhone == activePhone && activePhone.canTransfer());
    
public booleancanTransfer(Call heldCall, int subId)
Whether or not the phone specific to subId can do explicit call transfer in the current phone state--that is, one call holding and one call active.

return
true if the phone can do explicit call transfer; false otherwise.

        Phone activePhone = null;
        Phone heldPhone = null;

        if (hasActiveFgCall(subId)) {
            activePhone = getActiveFgCall(subId).getPhone();
        }

        if (heldCall != null) {
            heldPhone = heldCall.getPhone();
        }

        return (heldPhone == activePhone && activePhone.canTransfer());
    
public voidclearDisconnected()
clear disconnect connection for each phone

        for(Phone phone : mPhones) {
            phone.clearDisconnected();
        }
    
public voidclearDisconnected(int subId)
clear disconnect connection for a phone specific to the provided subId

        for(Phone phone : mPhones) {
            if (phone.getSubId() == subId) {
                phone.clearDisconnected();
            }
        }
    
public voidconference(Call heldCall)
Conferences holding and active. Conference occurs asynchronously and may fail. Final notification occurs via {@link #registerForPreciseCallStateChanged(android.os.Handler, int, java.lang.Object) registerForPreciseCallStateChanged()}.

exception
CallStateException if canConference() would return false. In these cases, this operation may not be performed.

        int subId  = heldCall.getPhone().getSubId();

        if (VDBG) {
            Rlog.d(LOG_TAG, "conference(" +heldCall + ")");
            Rlog.d(LOG_TAG, toString());
        }

        Phone fgPhone = getFgPhone(subId);
        if (fgPhone != null) {
            if (fgPhone instanceof SipPhone) {
                ((SipPhone) fgPhone).conference(heldCall);
            } else if (canConference(heldCall)) {
                fgPhone.conference();
            } else {
                throw(new CallStateException("Can't conference foreground and selected background call"));
            }
        } else {
            Rlog.d(LOG_TAG, "conference: fgPhone=null");
        }

        if (VDBG) {
            Rlog.d(LOG_TAG, "End conference(" +heldCall + ")");
            Rlog.d(LOG_TAG, toString());
        }

    
public Connectiondial(Phone phone, java.lang.String dialString, int videoState)
Initiate a new voice connection. This happens asynchronously, so you cannot assume the audio path is connected (or a call index has been assigned) until PhoneStateChanged notification has occurred.

exception
CallStateException if a new outgoing call is not currently possible because no more call slots exist or a call exists that is dialing, alerting, ringing, or waiting. Other errors are handled asynchronously.

        Phone basePhone = getPhoneBase(phone);
        int subId = phone.getSubId();
        Connection result;

        if (VDBG) {
            Rlog.d(LOG_TAG, " dial(" + basePhone + ", "+ dialString + ")" +
                    " subId = " + subId);
            Rlog.d(LOG_TAG, toString());
        }

        if (!canDial(phone)) {
            /*
             * canDial function only checks whether the phone can make a new call.
             * InCall MMI commmands are basically supplementary services
             * within a call eg: call hold, call deflection, explicit call transfer etc.
             */
            String newDialString = PhoneNumberUtils.stripSeparators(dialString);
            if (basePhone.handleInCallMmiCommands(newDialString)) {
                return null;
            } else {
                throw new CallStateException("cannot dial in current state");
            }
        }

        if ( hasActiveFgCall(subId) ) {
            Phone activePhone = getActiveFgCall(subId).getPhone();
            boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());

            if (DBG) {
                Rlog.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == basePhone));
            }

            // Manipulation between IMS phone and its owner
            // will be treated in GSM/CDMA phone.
            Phone vPhone = basePhone.getImsPhone();
            if (activePhone != basePhone
                    && (vPhone == null || vPhone != activePhone)) {
                if (hasBgCall) {
                    Rlog.d(LOG_TAG, "Hangup");
                    getActiveFgCall(subId).hangup();
                } else {
                    Rlog.d(LOG_TAG, "Switch");
                    activePhone.switchHoldingAndActive();
                }
            }
        }

        // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
        //mIsEccDialing = PhoneNumberUtils.isEmergencyNumber(dialString);

        result = basePhone.dial(dialString, videoState);

        if (VDBG) {
            Rlog.d(LOG_TAG, "End dial(" + basePhone + ", "+ dialString + ")");
            Rlog.d(LOG_TAG, toString());
        }

        return result;
    
public Connectiondial(Phone phone, java.lang.String dialString, UUSInfo uusInfo, int videoState)
Initiate a new voice connection. This happens asynchronously, so you cannot assume the audio path is connected (or a call index has been assigned) until PhoneStateChanged notification has occurred.

exception
CallStateException if a new outgoing call is not currently possible because no more call slots exist or a call exists that is dialing, alerting, ringing, or waiting. Other errors are handled asynchronously.

        return phone.dial(dialString, uusInfo, videoState);
    
public voidexplicitCallTransfer(Call heldCall)
Connects the held call and active call Disconnects the subscriber from both calls Explicit Call Transfer occurs asynchronously and may fail. Final notification occurs via {@link #registerForPreciseCallStateChanged(android.os.Handler, int, java.lang.Object) registerForPreciseCallStateChanged()}.

exception
CallStateException if canTransfer() would return false. In these cases, this operation may not be performed.

        if (VDBG) {
            Rlog.d(LOG_TAG, " explicitCallTransfer(" + heldCall + ")");
            Rlog.d(LOG_TAG, toString());
        }

        if (canTransfer(heldCall)) {
            heldCall.getPhone().explicitCallTransfer();
        }

        if (VDBG) {
            Rlog.d(LOG_TAG, "End explicitCallTransfer(" + heldCall + ")");
            Rlog.d(LOG_TAG, toString());
        }

    
public CallgetActiveFgCall()
return the active foreground call from foreground calls Active call means the call is NOT in Call.State.IDLE 1. If there is active foreground call, return it 2. If there is no active foreground call, return the foreground call associated with default phone, which state is IDLE. 3. If there is no phone registered at all, return null.

        Call call = getFirstNonIdleCall(mForegroundCalls);
        if (call == null) {
            call = (mDefaultPhone == null)
                    ? null
                    : mDefaultPhone.getForegroundCall();
        }
        return call;
    
public CallgetActiveFgCall(int subId)

        Call call = getFirstNonIdleCall(mForegroundCalls, subId);
        if (call == null) {
            Phone phone = getPhone(subId);
            call = (phone == null)
                    ? null
                    : phone.getForegroundCall();
        }
        return call;
    
public Call.StategetActiveFgCallState()

return
the state of active foreground call return IDLE if there is no active foreground call

        Call fgCall = getActiveFgCall();

        if (fgCall != null) {
            return fgCall.getState();
        }

        return Call.State.IDLE;
    
public Call.StategetActiveFgCallState(int subId)

        Call fgCall = getActiveFgCall(subId);

        if (fgCall != null) {
            return fgCall.getState();
        }

        return Call.State.IDLE;
    
public java.util.ListgetAllPhones()
Returns all the registered phone objects.

return
all the registered phone objects.

        return Collections.unmodifiableList(mPhones);
    
public java.util.ListgetBackgroundCalls()

return
list of all background calls

        return Collections.unmodifiableList(mBackgroundCalls);
    
public java.util.ListgetBgCallConnections()

return
the connections of active background call return empty list if there is no active background call

        Call bgCall = getFirstActiveBgCall();
        if ( bgCall != null) {
            return bgCall.getConnections();
        }
        return mEmptyConnections;
    
public java.util.ListgetBgCallConnections(int subId)

return
the connections of active background call return empty list if there is no active background call

        Call bgCall = getFirstActiveBgCall(subId);
        if ( bgCall != null) {
            return bgCall.getConnections();
        }
        return mEmptyConnections;
    
public PhonegetBgPhone()

return
the phone associated with the background call

        return getFirstActiveBgCall().getPhone();
    
public PhonegetBgPhone(int subId)

return
the phone associated with the background call of a particular subId

        return getFirstActiveBgCall(subId).getPhone();
    
private android.content.ContextgetContext()

        Phone defaultPhone = getDefaultPhone();
        return ((defaultPhone == null) ? null : defaultPhone.getContext());
    
public PhonegetDefaultPhone()
return the default phone or null if no phone available

        return mDefaultPhone;
    
public java.util.ListgetFgCallConnections()

return
the connections of active foreground call return empty list if there is no active foreground call

        Call fgCall = getActiveFgCall();
        if ( fgCall != null) {
            return fgCall.getConnections();
        }
        return mEmptyConnections;
    
public java.util.ListgetFgCallConnections(int subId)

return
the connections of active foreground call return empty list if there is no active foreground call

        Call fgCall = getActiveFgCall(subId);
        if ( fgCall != null) {
            return fgCall.getConnections();
        }
        return mEmptyConnections;
    
public ConnectiongetFgCallLatestConnection()

return
the latest connection of active foreground call return null if there is no active foreground call

        Call fgCall = getActiveFgCall();
        if ( fgCall != null) {
            return fgCall.getLatestConnection();
        }
        return null;
    
public ConnectiongetFgCallLatestConnection(int subId)

return
the latest connection of active foreground call return null if there is no active foreground call

        Call fgCall = getActiveFgCall(subId);
        if ( fgCall != null) {
            return fgCall.getLatestConnection();
        }
        return null;
    
public PhonegetFgPhone()

return
the phone associated with the foreground call

        return getActiveFgCall().getPhone();
    
public PhonegetFgPhone(int subId)

return
the phone associated with the foreground call of a particular subId

        return getActiveFgCall(subId).getPhone();
    
public CallgetFirstActiveBgCall()
return one active background call from background calls Active call means the call is NOT idle defined by Call.isIdle() 1. If there is only one active background call, return it 2. If there is more than one active background call, return the first one 3. If there is no active background call, return the background call associated with default phone, which state is IDLE. 4. If there is no background call at all, return null. Complete background calls list can be get by getBackgroundCalls()

        Call call = getFirstNonIdleCall(mBackgroundCalls);
        if (call == null) {
            call = (mDefaultPhone == null)
                    ? null
                    : mDefaultPhone.getBackgroundCall();
        }
        return call;
    
public CallgetFirstActiveBgCall(int subId)
return one active background call from background calls of the requested subId. Active call means the call is NOT idle defined by Call.isIdle() 1. If there is only one active background call on given sub or on SIP Phone, return it 2. If there is more than one active background call, return the background call associated with the active sub. 3. If there is no background call at all, return null. Complete background calls list can be get by getBackgroundCalls()

        Phone phone = getPhone(subId);
        if (hasMoreThanOneHoldingCall(subId)) {
            return phone.getBackgroundCall();
        } else {
            Call call = getFirstNonIdleCall(mBackgroundCalls, subId);
            if (call == null) {
                call = (phone == null)
                        ? null
                        : phone.getBackgroundCall();
            }
            return call;
        }
    
private CallgetFirstActiveCall(java.util.ArrayList calls)

return
the first active call from a call list

        for (Call call : calls) {
            if (!call.isIdle()) {
                return call;
            }
        }
        return null;
    
private CallgetFirstActiveCall(java.util.ArrayList calls, int subId)

return
the first active call from a call list

        for (Call call : calls) {
            if ((!call.isIdle()) && ((call.getPhone().getSubId() == subId) ||
                    (call.getPhone() instanceof SipPhone))) {
                return call;
            }
        }
        return null;
    
public CallgetFirstActiveRingingCall()
return one active ringing call from ringing calls Active call means the call is NOT idle defined by Call.isIdle() 1. If there is only one active ringing call, return it 2. If there is more than one active ringing call, return the first one 3. If there is no active ringing call, return the ringing call associated with default phone, which state is IDLE. 4. If there is no ringing call at all, return null. Complete ringing calls list can be get by getRingingCalls()

        Call call = getFirstNonIdleCall(mRingingCalls);
        if (call == null) {
            call = (mDefaultPhone == null)
                    ? null
                    : mDefaultPhone.getRingingCall();
        }
        return call;
    
public CallgetFirstActiveRingingCall(int subId)

        Phone phone = getPhone(subId);
        Call call = getFirstNonIdleCall(mRingingCalls, subId);
        if (call == null) {
            call = (phone == null)
                    ? null
                    : phone.getRingingCall();
        }
        return call;
    
private CallgetFirstCallOfState(java.util.ArrayList calls, Call.State state)

return
the first call in a the Call.state from a call list

        for (Call call : calls) {
            if (call.getState() == state) {
                return call;
            }
        }
        return null;
    
private CallgetFirstCallOfState(java.util.ArrayList calls, Call.State state, int subId)

return
the first call in a the Call.state from a call list

        for (Call call : calls) {
            if ((call.getState() == state) ||
                ((call.getPhone().getSubId() == subId) ||
                (call.getPhone() instanceof SipPhone))) {
                return call;
            }
        }
        return null;
    
private CallgetFirstNonIdleCall(java.util.List calls)

        Call result = null;
        for (Call call : calls) {
            if (!call.isIdle()) {
                return call;
            } else if (call.getState() != Call.State.IDLE) {
                if (result == null) result = call;
            }
        }
        return result;
    
private CallgetFirstNonIdleCall(java.util.List calls, int subId)

        Call result = null;
        for (Call call : calls) {
            if ((call.getPhone().getSubId() == subId) ||
                    (call.getPhone() instanceof SipPhone)) {
                if (!call.isIdle()) {
                    return call;
                } else if (call.getState() != Call.State.IDLE) {
                    if (result == null) result = call;
                }
            }
        }
        return result;
    
public java.util.ListgetForegroundCalls()

return
list of all foreground calls

        return Collections.unmodifiableList(mForegroundCalls);
    
public static com.android.internal.telephony.CallManagergetInstance()
get singleton instance of CallManager

return
CallManager

        return INSTANCE;
    
public booleangetMute()
Gets current mute status. Use {@link #registerForPreciseCallStateChanged(android.os.Handler, int, java.lang.Object) registerForPreciseCallStateChanged()} as a change notifcation, although presently phone state changed is not fired when setMute() is called.

return
true is muting, false is unmuting

        if (hasActiveFgCall()) {
            return getActiveFgCall().getPhone().getMute();
        } else if (hasActiveBgCall()) {
            return getFirstActiveBgCall().getPhone().getMute();
        }
        return false;
    
public java.util.ListgetPendingMmiCodes(Phone phone)
Returns a list of MMI codes that are pending for a phone. (They have initiated but have not yet completed). Presently there is only ever one. Use registerForMmiInitiate and registerForMmiComplete for change notification.

return
null if phone doesn't have or support mmi code

        Rlog.e(LOG_TAG, "getPendingMmiCodes not implemented");
        return null;
    
private PhonegetPhone(int subId)
get Phone object corresponds to subId

return
Phone

        Phone p = null;
        for (Phone phone : mPhones) {
            if (phone.getSubId() == subId && !(phone instanceof ImsPhone)) {
                p = phone;
                break;
            }
        }
        return p;
    
private static PhonegetPhoneBase(Phone phone)
Get the corresponding PhoneBase obj

param
phone a Phone object
return
the corresponding PhoneBase obj in Phone if Phone is a PhoneProxy obj or the Phone itself if Phone is not a PhoneProxy obj

        if (phone instanceof PhoneProxy) {
            return phone.getForegroundCall().getPhone();
        }
        return phone;
    
public PhonegetPhoneInCall()

return
the phone associated with any call

        Phone phone = null;
        if (!getFirstActiveRingingCall().isIdle()) {
            phone = getFirstActiveRingingCall().getPhone();
        } else if (!getActiveFgCall().isIdle()) {
            phone = getActiveFgCall().getPhone();
        } else {
            // If BG call is idle, we return default phone
            phone = getFirstActiveBgCall().getPhone();
        }
        return phone;
    
public PhonegetPhoneInCall(int subId)

        Phone phone = null;
        if (!getFirstActiveRingingCall(subId).isIdle()) {
            phone = getFirstActiveRingingCall(subId).getPhone();
        } else if (!getActiveFgCall(subId).isIdle()) {
            phone = getActiveFgCall(subId).getPhone();
        } else {
            // If BG call is idle, we return default phone
            phone = getFirstActiveBgCall(subId).getPhone();
        }
        return phone;
    
public java.util.ListgetRingingCalls()

return
list of all ringing calls

        return Collections.unmodifiableList(mRingingCalls);
    
public PhonegetRingingPhone()

return
the phone associated with the ringing call

        return getFirstActiveRingingCall().getPhone();
    
public PhonegetRingingPhone(int subId)

return
the phone associated with the ringing call of a particular subId

        return getFirstActiveRingingCall(subId).getPhone();
    
public intgetServiceState(int subId)

return
the Phone service state corresponds to subId

        int resultState = ServiceState.STATE_OUT_OF_SERVICE;

        for (Phone phone : mPhones) {
            if (phone.getSubId() == subId) {
                int serviceState = phone.getServiceState().getState();
                if (serviceState == ServiceState.STATE_IN_SERVICE) {
                    // IN_SERVICE has the highest priority
                    resultState = serviceState;
                    break;
                } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
                    // OUT_OF_SERVICE replaces EMERGENCY_ONLY and POWER_OFF
                    // Note: EMERGENCY_ONLY is not in use at this moment
                    if ( resultState == ServiceState.STATE_EMERGENCY_ONLY ||
                            resultState == ServiceState.STATE_POWER_OFF) {
                        resultState = serviceState;
                    }
                } else if (serviceState == ServiceState.STATE_EMERGENCY_ONLY) {
                    if (resultState == ServiceState.STATE_POWER_OFF) {
                        resultState = serviceState;
                    }
                }
            }
        }
        return resultState;
    
public intgetServiceState()

return
the service state of CallManager, which represents the highest priority state of all the service states of phones The priority is defined as STATE_IN_SERIVCE > STATE_OUT_OF_SERIVCE > STATE_EMERGENCY > STATE_POWER_OFF

        int resultState = ServiceState.STATE_OUT_OF_SERVICE;

        for (Phone phone : mPhones) {
            int serviceState = phone.getServiceState().getState();
            if (serviceState == ServiceState.STATE_IN_SERVICE) {
                // IN_SERVICE has the highest priority
                resultState = serviceState;
                break;
            } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
                // OUT_OF_SERVICE replaces EMERGENCY_ONLY and POWER_OFF
                // Note: EMERGENCY_ONLY is not in use at this moment
                if ( resultState == ServiceState.STATE_EMERGENCY_ONLY ||
                        resultState == ServiceState.STATE_POWER_OFF) {
                    resultState = serviceState;
                }
            } else if (serviceState == ServiceState.STATE_EMERGENCY_ONLY) {
                if (resultState == ServiceState.STATE_POWER_OFF) {
                    resultState = serviceState;
                }
            }
        }
        return resultState;
    
public PhoneConstants.StategetState()
Get current coarse-grained voice call state. If the Call Manager has an active call and call waiting occurs, then the phone state is RINGING not OFFHOOK

        PhoneConstants.State s = PhoneConstants.State.IDLE;

        for (Phone phone : mPhones) {
            if (phone.getState() == PhoneConstants.State.RINGING) {
                s = PhoneConstants.State.RINGING;
            } else if (phone.getState() == PhoneConstants.State.OFFHOOK) {
                if (s == PhoneConstants.State.IDLE) s = PhoneConstants.State.OFFHOOK;
            }
        }
        return s;
    
public PhoneConstants.StategetState(int subId)
Get current coarse-grained voice call state on a subId. If the Call Manager has an active call and call waiting occurs, then the phone state is RINGING not OFFHOOK

        PhoneConstants.State s = PhoneConstants.State.IDLE;

        for (Phone phone : mPhones) {
            if (phone.getSubId() == subId) {
                if (phone.getState() == PhoneConstants.State.RINGING) {
                    s = PhoneConstants.State.RINGING;
                } else if (phone.getState() == PhoneConstants.State.OFFHOOK) {
                    if (s == PhoneConstants.State.IDLE) s = PhoneConstants.State.OFFHOOK;
                }
            }
        }
        return s;
    
public voidhangupForegroundResumeBackground(Call heldCall)
Hangup foreground call and resume the specific background call Note: this is noop if there is no foreground call or the heldCall is null

param
heldCall to become foreground
throws
CallStateException

        Phone foregroundPhone = null;
        Phone backgroundPhone = null;

        if (VDBG) {
            Rlog.d(LOG_TAG, "hangupForegroundResumeBackground(" +heldCall + ")");
            Rlog.d(LOG_TAG, toString());
        }

        if (hasActiveFgCall()) {
            foregroundPhone = getFgPhone();
            if (heldCall != null) {
                backgroundPhone = heldCall.getPhone();
                if (foregroundPhone == backgroundPhone) {
                    getActiveFgCall().hangup();
                } else {
                // the call to be hangup and resumed belongs to different phones
                    getActiveFgCall().hangup();
                    switchHoldingAndActive(heldCall);
                }
            }
        }

        if (VDBG) {
            Rlog.d(LOG_TAG, "End hangupForegroundResumeBackground(" +heldCall + ")");
            Rlog.d(LOG_TAG, toString());
        }
    
public booleanhasActiveBgCall()
Return true if there is at least one active background call

        // TODO since hasActiveBgCall may get called often
        // better to cache it to improve performance
        return (getFirstActiveCall(mBackgroundCalls) != null);
    
public booleanhasActiveBgCall(int subId)
Return true if there is at least one active background call on a particular subId or an active sip call

        // TODO since hasActiveBgCall may get called often
        // better to cache it to improve performance
        return (getFirstActiveCall(mBackgroundCalls, subId) != null);
    
public booleanhasActiveFgCall()
Return true if there is at least one active foreground call

        return (getFirstActiveCall(mForegroundCalls) != null);
    
public booleanhasActiveFgCall(int subId)
Return true if there is at least one active foreground call on a particular subId or an active sip call

        return (getFirstActiveCall(mForegroundCalls, subId) != null);
    
public booleanhasActiveRingingCall()
Return true if there is at least one active ringing call

        return (getFirstActiveCall(mRingingCalls) != null);
    
public booleanhasActiveRingingCall(int subId)
Return true if there is at least one active ringing call

        return (getFirstActiveCall(mRingingCalls, subId) != null);
    
public booleanhasDisconnectedBgCall()

return
true if there is at least one background call in disconnected state

        return (getFirstCallOfState(mBackgroundCalls, Call.State.DISCONNECTED) != null);
    
public booleanhasDisconnectedBgCall(int subId)

return
true if there is at least one background call in disconnected state

        return (getFirstCallOfState(mBackgroundCalls, Call.State.DISCONNECTED,
                subId) != null);
    
public booleanhasDisconnectedFgCall()

return
true if there is at least one Foreground call in disconnected state

        return (getFirstCallOfState(mForegroundCalls, Call.State.DISCONNECTED) != null);
    
public booleanhasDisconnectedFgCall(int subId)

return
true if there is at least one Foreground call in disconnected state

        return (getFirstCallOfState(mForegroundCalls, Call.State.DISCONNECTED,
                subId) != null);
    
private booleanhasMoreThanOneHoldingCall(int subId)

return
true if more than one active background call exists on the provided subId. This checks for the background calls on provided subId and also background calls on SIP Phone.

        int count = 0;
        for (Call call : mBackgroundCalls) {
            if ((call.getState() == Call.State.HOLDING) &&
                ((call.getPhone().getSubId() == subId) ||
                (call.getPhone() instanceof SipPhone))) {
                if (++count > 1) return true;
            }
        }
        return false;
    
private booleanhasMoreThanOneRingingCall()

        int count = 0;
        for (Call call : mRingingCalls) {
            if (call.getState().isRinging()) {
                if (++count > 1) return true;
            }
        }
        return false;
    
private booleanhasMoreThanOneRingingCall(int subId)

return
true if more than one active ringing call exists on the active subId. This checks for the active calls on provided subId and also active calls on SIP Phone.

        int count = 0;
        for (Call call : mRingingCalls) {
            if ((call.getState().isRinging()) &&
                ((call.getPhone().getSubId() == subId) ||
                (call.getPhone() instanceof SipPhone))) {
                if (++count > 1) return true;
            }
        }
        return false;
    
public static booleanisSamePhone(Phone p1, Phone p2)
Check if two phones refer to the same PhoneBase obj Note: PhoneBase, not PhoneProxy, is to be used inside of CallManager Both PhoneBase and PhoneProxy implement Phone interface, so they have same phone APIs, such as dial(). The real implementation, for example in GSM, is in GSMPhone as extend from PhoneBase, so that foregroundCall.getPhone() returns GSMPhone obj. On the other hand, PhoneFactory.getDefaultPhone() returns PhoneProxy obj, which has a class member of GSMPhone. So for phone returned by PhoneFacotry, which is used by PhoneApp, phone.getForegroundCall().getPhone() != phone but isSamePhone(phone, phone.getForegroundCall().getPhone()) == true

param
p1 is the first Phone obj
param
p2 is the second Phone obj
return
true if p1 and p2 refer to the same phone

        return (getPhoneBase(p1) == getPhoneBase(p2));
    
public voidregisterForCallWaiting(android.os.Handler h, int what, java.lang.Object obj)
Register for notifications when CDMA call waiting comes

param
h Handler that receives the notification message.
param
what User-defined message code.
param
obj User object.

        mCallWaitingRegistrants.addUnique(h, what, obj);
    
public voidregisterForCdmaOtaStatusChange(android.os.Handler h, int what, java.lang.Object obj)
Register for notifications when CDMA OTA Provision status change

param
h Handler that receives the notification message.
param
what User-defined message code.
param
obj User object.

        mCdmaOtaStatusChangeRegistrants.addUnique(h, what, obj);
    
public voidregisterForDisconnect(android.os.Handler h, int what, java.lang.Object obj)
Notifies when a voice connection has disconnected, either due to local or remote hangup or error. Messages received from this will have the following members:

  • Message.obj will be an AsyncResult
  • AsyncResult.userObj = obj
  • AsyncResult.result = a Connection object that is no longer connected.

        mDisconnectRegistrants.addUnique(h, what, obj);
    
public voidregisterForDisplayInfo(android.os.Handler h, int what, java.lang.Object obj)
Register for display information notifications from the network. Message.obj will contain an AsyncResult. AsyncResult.result will be a SuppServiceNotification instance.

param
h Handler that receives the notification message.
param
what User-defined message code.
param
obj User object.

        mDisplayInfoRegistrants.addUnique(h, what, obj);
    
public voidregisterForEcmTimerReset(android.os.Handler h, int what, java.lang.Object obj)
Registration point for Ecm timer reset

param
h handler to notify
param
what user-defined message code
param
obj placed in Message.obj

        mEcmTimerResetRegistrants.addUnique(h, what, obj);
    
public voidregisterForInCallVoicePrivacyOff(android.os.Handler h, int what, java.lang.Object obj)
Register for notifications when a sInCall VoicePrivacy is disabled

param
h Handler that receives the notification message.
param
what User-defined message code.
param
obj User object.

        mInCallVoicePrivacyOffRegistrants.addUnique(h, what, obj);
    
public voidregisterForInCallVoicePrivacyOn(android.os.Handler h, int what, java.lang.Object obj)
Register for notifications when a sInCall VoicePrivacy is enabled

param
h Handler that receives the notification message.
param
what User-defined message code.
param
obj User object.

        mInCallVoicePrivacyOnRegistrants.addUnique(h, what, obj);
    
public voidregisterForIncomingRing(android.os.Handler h, int what, java.lang.Object obj)
Notifies when an incoming call rings.

Messages received from this: Message.obj will be an AsyncResult AsyncResult.userObj = obj AsyncResult.result = a Connection.

        mIncomingRingRegistrants.addUnique(h, what, obj);
    
public voidregisterForMmiComplete(android.os.Handler h, int what, java.lang.Object obj)
Register for notifications that an MMI request has completed its network activity and is in its final state. This may mean a state of COMPLETE, FAILED, or CANCELLED. Message.obj will contain an AsyncResult. obj.result will be an "MmiCode" object

        mMmiCompleteRegistrants.addUnique(h, what, obj);
    
public voidregisterForMmiInitiate(android.os.Handler h, int what, java.lang.Object obj)
Register for notifications of initiation of a new MMI code request. MMI codes for GSM are discussed in 3GPP TS 22.030.

Example: If Phone.dial is called with "*#31#", then the app will be notified here.

The returned Message.obj will contain an AsyncResult. obj.result will be an "MmiCode" object.

        mMmiInitiateRegistrants.addUnique(h, what, obj);
    
public voidregisterForNewRingingConnection(android.os.Handler h, int what, java.lang.Object obj)
Notifies when a new ringing or waiting connection has appeared.

Messages received from this: Message.obj will be an AsyncResult AsyncResult.userObj = obj AsyncResult.result = a Connection.

Please check Connection.isRinging() to make sure the Connection has not dropped since this message was posted. If Connection.isRinging() is true, then Connection.getCall() == Phone.getRingingCall()

        mNewRingingConnectionRegistrants.addUnique(h, what, obj);
    
public voidregisterForOnHoldTone(android.os.Handler h, int what, java.lang.Object obj)
Notifies when out-band on-hold tone is needed.

Messages received from this: Message.obj will be an AsyncResult AsyncResult.userObj = obj AsyncResult.result = boolean, true to start play on-hold tone and false to stop.

        mOnHoldToneRegistrants.addUnique(h, what, obj);
    
private voidregisterForPhoneStates(Phone phone)

        // We need to keep a mapping of handler to Phone for proper unregistration.
        // TODO: Clean up this solution as it is just a work around for each Phone instance
        // using the same Handler to register with the RIL. When time permits, we should consider
        // moving the handler (or the reference ot the handler) into the Phone object.
        // See b/17414427.
        CallManagerHandler handler = mHandlerMap.get(phone);
        if (handler != null) {
            Rlog.d(LOG_TAG, "This phone has already been registered.");
            return;
        }

        // New registration, create a new handler instance and register the phone.
        handler = new CallManagerHandler();
        mHandlerMap.put(phone, handler);

        // for common events supported by all phones
        phone.registerForPreciseCallStateChanged(handler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
        phone.registerForDisconnect(handler, EVENT_DISCONNECT, null);
        phone.registerForNewRingingConnection(handler, EVENT_NEW_RINGING_CONNECTION, null);
        phone.registerForUnknownConnection(handler, EVENT_UNKNOWN_CONNECTION, null);
        phone.registerForIncomingRing(handler, EVENT_INCOMING_RING, null);
        phone.registerForRingbackTone(handler, EVENT_RINGBACK_TONE, null);
        phone.registerForInCallVoicePrivacyOn(handler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);
        phone.registerForInCallVoicePrivacyOff(handler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);
        phone.registerForDisplayInfo(handler, EVENT_DISPLAY_INFO, null);
        phone.registerForSignalInfo(handler, EVENT_SIGNAL_INFO, null);
        phone.registerForResendIncallMute(handler, EVENT_RESEND_INCALL_MUTE, null);
        phone.registerForMmiInitiate(handler, EVENT_MMI_INITIATE, null);
        phone.registerForMmiComplete(handler, EVENT_MMI_COMPLETE, null);
        phone.registerForSuppServiceFailed(handler, EVENT_SUPP_SERVICE_FAILED, null);
        phone.registerForServiceStateChanged(handler, EVENT_SERVICE_STATE_CHANGED, null);
        // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
        //phone.registerForRadioOffOrNotAvailable(handler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);

        // for events supported only by GSM, CDMA and IMS phone
        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM ||
                phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ||
                phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
            phone.setOnPostDialCharacter(handler, EVENT_POST_DIAL_CHARACTER, null);
        }

        // for events supported only by CDMA phone
        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ){
            phone.registerForCdmaOtaStatusChange(handler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
            phone.registerForSubscriptionInfoReady(handler, EVENT_SUBSCRIPTION_INFO_READY, null);
            phone.registerForCallWaiting(handler, EVENT_CALL_WAITING, null);
            phone.registerForEcmTimerReset(handler, EVENT_ECM_TIMER_RESET, null);
        }

        // for events supported only by IMS phone
        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
            phone.registerForOnHoldTone(handler, EVENT_ONHOLD_TONE, null);
            phone.registerForSuppServiceFailed(handler, EVENT_SUPP_SERVICE_FAILED, null);
            phone.registerForTtyModeReceived(handler, EVENT_TTY_MODE_RECEIVED, null);
        }
    
public voidregisterForPostDialCharacter(android.os.Handler h, int what, java.lang.Object obj)
Sets an event to be fired when the telephony system processes a post-dial character on an outgoing call.

Messages of type what will be sent to h. The obj field of these Message's will be instances of AsyncResult. Message.obj.result will be a Connection object.

Message.arg1 will be the post dial character being processed, or 0 ('\0') if end of string.

If Connection.getPostDialState() == WAIT, the application must call {@link com.android.internal.telephony.Connection#proceedAfterWaitChar() Connection.proceedAfterWaitChar()} or {@link com.android.internal.telephony.Connection#cancelPostDial() Connection.cancelPostDial()} for the telephony system to continue playing the post-dial DTMF sequence.

If Connection.getPostDialState() == WILD, the application must call {@link com.android.internal.telephony.Connection#proceedAfterWildChar Connection.proceedAfterWildChar()} or {@link com.android.internal.telephony.Connection#cancelPostDial() Connection.cancelPostDial()} for the telephony system to continue playing the post-dial DTMF sequence.

        mPostDialCharacterRegistrants.addUnique(h, what, obj);
    
public voidregisterForPreciseCallStateChanged(android.os.Handler h, int what, java.lang.Object obj)
Register for getting notifications for change in the Call State {@link Call.State} This is called PreciseCallState because the call state is more precise than what can be obtained using the {@link PhoneStateListener} Resulting events will have an AsyncResult in Message.obj. AsyncResult.userData will be set to the obj argument here. The h parameter is held only by a weak reference.

        mPreciseCallStateRegistrants.addUnique(h, what, obj);
    
public voidregisterForResendIncallMute(android.os.Handler h, int what, java.lang.Object obj)
Registers the handler to reset the uplink mute state to get uplink audio.

        mResendIncallMuteRegistrants.addUnique(h, what, obj);
    
public voidregisterForRingbackTone(android.os.Handler h, int what, java.lang.Object obj)
Notifies when out-band ringback tone is needed.

Messages received from this: Message.obj will be an AsyncResult AsyncResult.userObj = obj AsyncResult.result = boolean, true to start play ringback tone and false to stop.

        mRingbackToneRegistrants.addUnique(h, what, obj);
    
public voidregisterForServiceStateChanged(android.os.Handler h, int what, java.lang.Object obj)
Register for ServiceState changed. Message.obj will contain an AsyncResult. AsyncResult.result will be a ServiceState instance

        mServiceStateChangedRegistrants.addUnique(h, what, obj);
    
public voidregisterForSignalInfo(android.os.Handler h, int what, java.lang.Object obj)
Register for signal information notifications from the network. Message.obj will contain an AsyncResult. AsyncResult.result will be a SuppServiceNotification instance.

param
h Handler that receives the notification message.
param
what User-defined message code.
param
obj User object.

        mSignalInfoRegistrants.addUnique(h, what, obj);
    
public voidregisterForSubscriptionInfoReady(android.os.Handler h, int what, java.lang.Object obj)
Registration point for subscription info ready

param
h handler to notify
param
what what code of message when delivered
param
obj placed in Message.obj

        mSubscriptionInfoReadyRegistrants.addUnique(h, what, obj);
    
public voidregisterForSuppServiceFailed(android.os.Handler h, int what, java.lang.Object obj)
Register for notifications when a supplementary service attempt fails. Message.obj will contain an AsyncResult.

param
h Handler that receives the notification message.
param
what User-defined message code.
param
obj User object.

        mSuppServiceFailedRegistrants.addUnique(h, what, obj);
    
public voidregisterForTtyModeReceived(android.os.Handler h, int what, java.lang.Object obj)
Register for TTY mode change notifications from the network. Message.obj will contain an AsyncResult. AsyncResult.result will be an Integer containing new mode.

param
h Handler that receives the notification message.
param
what User-defined message code.
param
obj User object.

        mTtyModeReceivedRegistrants.addUnique(h, what, obj);
    
public voidregisterForUnknownConnection(android.os.Handler h, int what, java.lang.Object obj)
Notifies when a previously untracked non-ringing/waiting connection has appeared. This is likely due to some other entity (eg, SIM card application) initiating a call.

        mUnknownConnectionRegistrants.addUnique(h, what, obj);
    
public booleanregisterPhone(Phone phone)
Register phone to CallManager

param
phone to be registered
return
true if register successfully

        Phone basePhone = getPhoneBase(phone);

        if (basePhone != null && !mPhones.contains(basePhone)) {

            if (DBG) {
                Rlog.d(LOG_TAG, "registerPhone(" +
                        phone.getPhoneName() + " " + phone + ")");
            }

            if (mPhones.isEmpty()) {
                mDefaultPhone = basePhone;
            }
            mPhones.add(basePhone);
            mRingingCalls.add(basePhone.getRingingCall());
            mBackgroundCalls.add(basePhone.getBackgroundCall());
            mForegroundCalls.add(basePhone.getForegroundCall());
            registerForPhoneStates(basePhone);
            return true;
        }
        return false;
    
public voidrejectCall(Call ringingCall)
Reject (ignore) a ringing call. In GSM, this means UDUB (User Determined User Busy). Reject occurs asynchronously, and final notification occurs via {@link #registerForPreciseCallStateChanged(android.os.Handler, int, java.lang.Object) registerForPreciseCallStateChanged()}.

exception
CallStateException when no call is ringing or waiting

        if (VDBG) {
            Rlog.d(LOG_TAG, "rejectCall(" +ringingCall + ")");
            Rlog.d(LOG_TAG, toString());
        }

        Phone ringingPhone = ringingCall.getPhone();

        ringingPhone.rejectCall();

        if (VDBG) {
            Rlog.d(LOG_TAG, "End rejectCall(" +ringingCall + ")");
            Rlog.d(LOG_TAG, toString());
        }
    
public booleansendBurstDtmf(java.lang.String dtmfString, int on, int off, android.os.Message onComplete)
send burst DTMF tone, it can send the string as single character or multiple character ignore if there is no active call or not valid digits string. Valid digit means only includes characters ISO-LATIN characters 0-9, *, # The difference between sendDtmf and sendBurstDtmf is sendDtmf only sends one character, this api can send single character and multiple character, also, this api has response back to caller.

param
dtmfString is string representing the dialing digit(s) in the active call
param
on the DTMF ON length in milliseconds, or 0 for default
param
off the DTMF OFF length in milliseconds, or 0 for default
param
onComplete is the callback message when the action is processed by BP

        if (hasActiveFgCall()) {
            getActiveFgCall().getPhone().sendBurstDtmf(dtmfString, on, off, onComplete);
            return true;
        }
        return false;
    
public booleansendDtmf(char c)
Play a DTMF tone on the active call.

param
c should be one of 0-9, '*' or '#'. Other values will be silently ignored.
return
false if no active call or the active call doesn't support dtmf tone

        boolean result = false;

        if (VDBG) {
            Rlog.d(LOG_TAG, " sendDtmf(" + c + ")");
            Rlog.d(LOG_TAG, toString());
        }

        if (hasActiveFgCall()) {
            getActiveFgCall().getPhone().sendDtmf(c);
            result = true;
        }

        if (VDBG) {
            Rlog.d(LOG_TAG, "End sendDtmf(" + c + ")");
            Rlog.d(LOG_TAG, toString());
        }
        return result;
    
public booleansendUssdResponse(Phone phone, java.lang.String ussdMessge)
Sends user response to a USSD REQUEST message. An MmiCode instance representing this response is sent to handlers registered with registerForMmiInitiate.

param
ussdMessge Message to send in the response.
return
false if phone doesn't support ussd service

        Rlog.e(LOG_TAG, "sendUssdResponse not implemented");
        return false;
    
public voidsetEchoSuppressionEnabled()
Enables or disables echo suppression.

        if (VDBG) {
            Rlog.d(LOG_TAG, " setEchoSuppression()");
            Rlog.d(LOG_TAG, toString());
        }

        if (hasActiveFgCall()) {
            getActiveFgCall().getPhone().setEchoSuppressionEnabled();
        }

        if (VDBG) {
            Rlog.d(LOG_TAG, "End setEchoSuppression()");
            Rlog.d(LOG_TAG, toString());
        }
    
public voidsetMute(boolean muted)
Mutes or unmutes the microphone for the active call. The microphone is automatically unmuted if a call is answered, dialed, or resumed from a holding state.

param
muted true to mute the microphone, false to activate the microphone.

        if (VDBG) {
            Rlog.d(LOG_TAG, " setMute(" + muted + ")");
            Rlog.d(LOG_TAG, toString());
        }

        if (hasActiveFgCall()) {
            getActiveFgCall().getPhone().setMute(muted);
        }

        if (VDBG) {
            Rlog.d(LOG_TAG, "End setMute(" + muted + ")");
            Rlog.d(LOG_TAG, toString());
        }
    
public booleanstartDtmf(char c)
Start to paly a DTMF tone on the active call. or there is a playing DTMF tone.

param
c should be one of 0-9, '*' or '#'. Other values will be silently ignored.
return
false if no active call or the active call doesn't support dtmf tone

        boolean result = false;

        if (VDBG) {
            Rlog.d(LOG_TAG, " startDtmf(" + c + ")");
            Rlog.d(LOG_TAG, toString());
        }

        if (hasActiveFgCall()) {
            getActiveFgCall().getPhone().startDtmf(c);
            result = true;
        }

        if (VDBG) {
            Rlog.d(LOG_TAG, "End startDtmf(" + c + ")");
            Rlog.d(LOG_TAG, toString());
        }

        return result;
    
public voidstopDtmf()
Stop the playing DTMF tone. Ignored if there is no playing DTMF tone or no active call.

        if (VDBG) {
            Rlog.d(LOG_TAG, " stopDtmf()" );
            Rlog.d(LOG_TAG, toString());
        }

        if (hasActiveFgCall()) getFgPhone().stopDtmf();

        if (VDBG) {
            Rlog.d(LOG_TAG, "End stopDtmf()");
            Rlog.d(LOG_TAG, toString());
        }
    
public voidswitchHoldingAndActive(Call heldCall)
Places active call on hold, and makes held call active. Switch occurs asynchronously and may fail. There are 4 scenarios 1. only active call but no held call, aka, hold 2. no active call but only held call, aka, unhold 3. both active and held calls from same phone, aka, swap 4. active and held calls from different phones, aka, phone swap Final notification occurs via {@link #registerForPreciseCallStateChanged(android.os.Handler, int, java.lang.Object) registerForPreciseCallStateChanged()}.

exception
CallStateException if active call is ringing, waiting, or dialing/alerting, or heldCall can't be active. In these cases, this operation may not be performed.

        Phone activePhone = null;
        Phone heldPhone = null;

        if (VDBG) {
            Rlog.d(LOG_TAG, "switchHoldingAndActive(" +heldCall + ")");
            Rlog.d(LOG_TAG, toString());
        }

        if (hasActiveFgCall()) {
            activePhone = getActiveFgCall().getPhone();
        }

        if (heldCall != null) {
            heldPhone = heldCall.getPhone();
        }

        if (activePhone != null) {
            activePhone.switchHoldingAndActive();
        }

        if (heldPhone != null && heldPhone != activePhone) {
            heldPhone.switchHoldingAndActive();
        }

        if (VDBG) {
            Rlog.d(LOG_TAG, "End switchHoldingAndActive(" +heldCall + ")");
            Rlog.d(LOG_TAG, toString());
        }
    
public java.lang.StringtoString()

        Call call;
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
            b.append("CallManager {");
            b.append("\nstate = " + getState(i));
            call = getActiveFgCall(i);
            if (call != null) {
                b.append("\n- Foreground: " + getActiveFgCallState(i));
                b.append(" from " + call.getPhone());
                b.append("\n  Conn: ").append(getFgCallConnections(i));
            }
            call = getFirstActiveBgCall(i);
            if (call != null) {
                b.append("\n- Background: " + call.getState());
                b.append(" from " + call.getPhone());
                b.append("\n  Conn: ").append(getBgCallConnections(i));
            }
            call = getFirstActiveRingingCall(i);
            if (call != null) {
                b.append("\n- Ringing: " +call.getState());
                b.append(" from " + call.getPhone());
            }
        }

        for (Phone phone : getAllPhones()) {
            if (phone != null) {
                b.append("\nPhone: " + phone + ", name = " + phone.getPhoneName()
                        + ", state = " + phone.getState());
                call = phone.getForegroundCall();
                if (call != null) {
                    b.append("\n- Foreground: ").append(call);
                }
                call = phone.getBackgroundCall();
                if (call != null) {
                    b.append(" Background: ").append(call);
                }
                call = phone.getRingingCall();
                if (call != null) {
                    b.append(" Ringing: ").append(call);
                }
            }
        }
        b.append("\n}");
        return b.toString();
    
public voidunregisterForCallWaiting(android.os.Handler h)
Unregister for notifications when CDMA Call waiting comes

param
h Handler to be removed from the registrant list.

        mCallWaitingRegistrants.remove(h);
    
public voidunregisterForCdmaOtaStatusChange(android.os.Handler h)
Unregister for notifications when CDMA OTA Provision status change

param
h Handler to be removed from the registrant list.

        mCdmaOtaStatusChangeRegistrants.remove(h);
    
public voidunregisterForDisconnect(android.os.Handler h)
Unregisters for voice disconnection notification. Extraneous calls are tolerated silently

        mDisconnectRegistrants.remove(h);
    
public voidunregisterForDisplayInfo(android.os.Handler h)
Unregisters for display information notifications. Extraneous calls are tolerated silently

param
h Handler to be removed from the registrant list.

        mDisplayInfoRegistrants.remove(h);
    
public voidunregisterForEcmTimerReset(android.os.Handler h)
Unregister for notification for Ecm timer reset

param
h Handler to be removed from the registrant list.

        mEcmTimerResetRegistrants.remove(h);
    
public voidunregisterForInCallVoicePrivacyOff(android.os.Handler h)
Unregister for notifications when a sInCall VoicePrivacy is disabled

param
h Handler to be removed from the registrant list.

        mInCallVoicePrivacyOffRegistrants.remove(h);
    
public voidunregisterForInCallVoicePrivacyOn(android.os.Handler h)
Unregister for notifications when a sInCall VoicePrivacy is enabled

param
h Handler to be removed from the registrant list.

        mInCallVoicePrivacyOnRegistrants.remove(h);
    
public voidunregisterForIncomingRing(android.os.Handler h)
Unregisters for ring notification. Extraneous calls are tolerated silently

        mIncomingRingRegistrants.remove(h);
    
public voidunregisterForMmiComplete(android.os.Handler h)
Unregisters for MMI complete notification. Extraneous calls are tolerated silently

        mMmiCompleteRegistrants.remove(h);
    
public voidunregisterForMmiInitiate(android.os.Handler h)
Unregisters for new MMI initiate notification. Extraneous calls are tolerated silently

        mMmiInitiateRegistrants.remove(h);
    
public voidunregisterForNewRingingConnection(android.os.Handler h)
Unregisters for new ringing connection notification. Extraneous calls are tolerated silently

        mNewRingingConnectionRegistrants.remove(h);
    
public voidunregisterForOnHoldTone(android.os.Handler h)
Unregisters for on-hold tone notification.

        mOnHoldToneRegistrants.remove(h);
    
private voidunregisterForPhoneStates(Phone phone)

        // Make sure that we clean up our map of handlers to Phones.
        CallManagerHandler handler = mHandlerMap.get(phone);
        if (handler != null) {
            Rlog.e(LOG_TAG, "Could not find Phone handler for unregistration");
            return;
        }
        mHandlerMap.remove(phone);

        //  for common events supported by all phones
        phone.unregisterForPreciseCallStateChanged(handler);
        phone.unregisterForDisconnect(handler);
        phone.unregisterForNewRingingConnection(handler);
        phone.unregisterForUnknownConnection(handler);
        phone.unregisterForIncomingRing(handler);
        phone.unregisterForRingbackTone(handler);
        phone.unregisterForInCallVoicePrivacyOn(handler);
        phone.unregisterForInCallVoicePrivacyOff(handler);
        phone.unregisterForDisplayInfo(handler);
        phone.unregisterForSignalInfo(handler);
        phone.unregisterForResendIncallMute(handler);
        phone.unregisterForMmiInitiate(handler);
        phone.unregisterForMmiComplete(handler);
        phone.unregisterForSuppServiceFailed(handler);
        phone.unregisterForServiceStateChanged(handler);
        phone.unregisterForTtyModeReceived(handler);
        // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
        //phone.unregisterForRadioOffOrNotAvailable(handler);

        // for events supported only by GSM, CDMA and IMS phone
        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM ||
                phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ||
                phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
            phone.setOnPostDialCharacter(null, EVENT_POST_DIAL_CHARACTER, null);
        }

        // for events supported only by CDMA phone
        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ){
            phone.unregisterForCdmaOtaStatusChange(handler);
            phone.unregisterForSubscriptionInfoReady(handler);
            phone.unregisterForCallWaiting(handler);
            phone.unregisterForEcmTimerReset(handler);
        }

        // for events supported only by IMS phone
        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
            phone.unregisterForOnHoldTone(handler);
            phone.unregisterForSuppServiceFailed(handler);
        }
    
public voidunregisterForPostDialCharacter(android.os.Handler h)

        mPostDialCharacterRegistrants.remove(h);
    
public voidunregisterForPreciseCallStateChanged(android.os.Handler h)
Unregisters for voice call state change notifications. Extraneous calls are tolerated silently.

        mPreciseCallStateRegistrants.remove(h);
    
public voidunregisterForResendIncallMute(android.os.Handler h)
Unregisters for resend incall mute notifications.

        mResendIncallMuteRegistrants.remove(h);
    
public voidunregisterForRingbackTone(android.os.Handler h)
Unregisters for ringback tone notification.

        mRingbackToneRegistrants.remove(h);
    
public voidunregisterForServiceStateChanged(android.os.Handler h)
Unregisters for ServiceStateChange notification. Extraneous calls are tolerated silently

        mServiceStateChangedRegistrants.remove(h);
    
public voidunregisterForSignalInfo(android.os.Handler h)
Unregisters for signal information notifications. Extraneous calls are tolerated silently

param
h Handler to be removed from the registrant list.

        mSignalInfoRegistrants.remove(h);
    
public voidunregisterForSubscriptionInfoReady(android.os.Handler h)
Unregister for notifications for subscription info

param
h Handler to be removed from the registrant list.

        mSubscriptionInfoReadyRegistrants.remove(h);
    
public voidunregisterForSuppServiceFailed(android.os.Handler h)
Unregister for notifications when a supplementary service attempt fails. Extraneous calls are tolerated silently

param
h Handler to be removed from the registrant list.

        mSuppServiceFailedRegistrants.remove(h);
    
public voidunregisterForTtyModeReceived(android.os.Handler h)
Unregisters for TTY mode change notifications. Extraneous calls are tolerated silently

param
h Handler to be removed from the registrant list.

        mTtyModeReceivedRegistrants.remove(h);
    
public voidunregisterForUnknownConnection(android.os.Handler h)
Unregisters for unknown connection notifications.

        mUnknownConnectionRegistrants.remove(h);
    
public voidunregisterPhone(Phone phone)
unregister phone from CallManager

param
phone to be unregistered

        Phone basePhone = getPhoneBase(phone);

        if (basePhone != null && mPhones.contains(basePhone)) {

            if (DBG) {
                Rlog.d(LOG_TAG, "unregisterPhone(" +
                        phone.getPhoneName() + " " + phone + ")");
            }

            Phone vPhone = basePhone.getImsPhone();
            if (vPhone != null) {
               unregisterPhone(vPhone);
            }

            mPhones.remove(basePhone);
            mRingingCalls.remove(basePhone.getRingingCall());
            mBackgroundCalls.remove(basePhone.getBackgroundCall());
            mForegroundCalls.remove(basePhone.getForegroundCall());
            unregisterForPhoneStates(basePhone);
            if (basePhone == mDefaultPhone) {
                if (mPhones.isEmpty()) {
                    mDefaultPhone = null;
                } else {
                    mDefaultPhone = mPhones.get(0);
                }
            }
        }