Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62de98e1 authored by Hall Liu's avatar Hall Liu Committed by Gerrit Code Review
Browse files

Merge "Refactor the holding logic in ImsPhoneCallTracker"

parents a6d25ac6 e2c16567
Loading
Loading
Loading
Loading
+5 −141
Original line number Diff line number Diff line
@@ -16,20 +16,19 @@

package com.android.internal.telephony;

import com.android.internal.telephony.sip.SipPhone;

import android.content.Context;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
import android.os.RegistrantList;
import android.os.Registrant;
import android.telecom.VideoProfile;
import android.os.RegistrantList;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;

import com.android.internal.telephony.sip.SipPhone;

import java.util.ArrayList;
import java.util.Collections;
@@ -665,54 +664,6 @@ public class CallManager {
        phone.unregisterForSuppServiceFailed(handler);
    }

    /**
     * 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
     */
    public void acceptCall(Call ringingCall) throws CallStateException {
        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.STATE_AUDIO_ONLY);

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

    /**
     * Reject (ignore) a ringing call. In GSM, this means UDUB
     * (User Determined User Busy). Reject occurs asynchronously,
@@ -724,7 +675,6 @@ public class CallManager {
     */
    public void rejectCall(Call ringingCall) throws CallStateException {
        if (VDBG) {
            Rlog.d(LOG_TAG, "rejectCall(" +ringingCall + ")");
            Rlog.d(LOG_TAG, toString());
        }

@@ -738,92 +688,6 @@ public class CallManager {
        }
    }

    /**
     * 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.
     */
    public void switchHoldingAndActive(Call heldCall) throws CallStateException {
        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());
        }
    }

    /**
     * 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
     */
    public void hangupForegroundResumeBackground(Call heldCall) 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());
        }
    }

    /**
     * Whether or not the phone can conference in the current phone
     * state--that is, one call holding and one call active.
+22 −5
Original line number Diff line number Diff line
@@ -356,7 +356,7 @@ public class ImsPhone extends ImsPhoneBase {
    @Override
    public void
    switchHoldingAndActive() throws CallStateException {
        mCT.switchWaitingOrHoldingAndActive();
        throw new UnsupportedOperationException("Use hold() and unhold() instead.");
    }

    @Override
@@ -411,6 +411,23 @@ public class ImsPhone extends ImsPhoneBase {
        return mCT.isImsServiceReady();
    }

    /**
     * Hold the currently active call, possibly unholding a currently held call.
     * @throws CallStateException
     */
    public void holdActiveCall() throws CallStateException {
        mCT.holdActiveCall();
    }

    /**
     * Unhold the currently active call, possibly holding a currently active call.
     * If the call tracker is already in the middle of a hold operation, this is a noop.
     * @throws CallStateException
     */
    public void unholdHeldCall() throws CallStateException {
        mCT.unholdHeldCall();
    }

    private boolean handleCallDeflectionIncallSupplementaryService(
            String dialString) {
        if (dialString.length() > 1) {
@@ -494,8 +511,8 @@ public class ImsPhone extends ImsPhoneBase {
                    if (DBG) logd("MmiCode 1: hangup foreground");
                    mCT.hangup(call);
                } else {
                    if (DBG) logd("MmiCode 1: switchWaitingOrHoldingAndActive");
                    mCT.switchWaitingOrHoldingAndActive();
                    if (DBG) logd("MmiCode 1: holdActiveCallForWaitingCall");
                    mCT.holdActiveCallForWaitingCall();
                }
            }
        } catch (CallStateException e) {
@@ -522,8 +539,8 @@ public class ImsPhone extends ImsPhoneBase {
                    if (DBG) logd("MmiCode 2: accept ringing call");
                    mCT.acceptCall(ImsCallProfile.CALL_TYPE_VOICE);
                } else {
                    if (DBG) logd("MmiCode 2: switchWaitingOrHoldingAndActive");
                    mCT.switchWaitingOrHoldingAndActive();
                    if (DBG) logd("MmiCode 2: holdActiveCall");
                    mCT.holdActiveCall();
                }
            } catch (CallStateException e) {
                if (DBG) Rlog.d(LOG_TAG, "switch failed", e);
+200 −102

File changed.

Preview size limit exceeded, changes collapsed.

+16 −68
Original line number Diff line number Diff line
@@ -15,6 +15,22 @@
 */
package com.android.internal.telephony;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyChar;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
@@ -27,26 +43,9 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;

import java.lang.reflect.Field;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyChar;
import static org.mockito.Mockito.anyString;

public class CallManagerTest extends TelephonyTest {

    @Mock
@@ -152,12 +151,6 @@ public class CallManagerTest extends TelephonyTest {
        assertEquals(0, dialArgsCaptor.getValue().videoState);
    }

    @SmallTest @Test
    public void testBasicAcceptCall() throws Exception {
        CallManager.getInstance().acceptCall(mRingingCall);
        verify(mPhone, times(1)).acceptCall(anyInt());
    }

    @SmallTest @Test
    public void testBasicRejectCall() throws Exception {
        //verify can dial and dial function of the phone is being triggered
@@ -229,51 +222,6 @@ public class CallManagerTest extends TelephonyTest {
        verify(mPhone, times(1)).setMute(true);
    }

    @SmallTest @Test
    public void testSwitchHoldingAndActive() throws Exception {
        /* case 1: only active call */
        doReturn(false).when(mFgCall).isIdle();
        CallManager.getInstance().switchHoldingAndActive(null);
        verify(mPhone, times(1)).switchHoldingAndActive();
        /* case 2: no active call but only held call, aka, unhold */
        doReturn(true).when(mFgCall).isIdle();
        CallManager.getInstance().switchHoldingAndActive(mBgCall);
        verify(mPhone, times(2)).switchHoldingAndActive();
        /* case 3: both active and held calls from same phone, aka, swap */
        doReturn(false).when(mFgCall).isIdle();
        CallManager.getInstance().switchHoldingAndActive(mBgCall);
        verify(mPhone, times(3)).switchHoldingAndActive();
        GsmCdmaPhone mPhoneHold = Mockito.mock(GsmCdmaPhone.class);
        /* case 4: active and held calls from different phones, aka, phone swap */
        doReturn(mPhoneHold).when(mBgCall).getPhone();
        CallManager.getInstance().switchHoldingAndActive(mBgCall);
        verify(mPhone, times(4)).switchHoldingAndActive();
        verify(mPhoneHold, times(1)).switchHoldingAndActive();
    }

    @SmallTest @Test
    public void testHangupForegroundResumeBackground() throws Exception {
        CallManager.getInstance().hangupForegroundResumeBackground(mBgCall);
        /* no active fgCall */
        verify(mPhone, times(0)).switchHoldingAndActive();
        verify(mFgCall, times(0)).hangup();

        /* have active foreground call, get hanged up */
        doReturn(false).when(mFgCall).isIdle();
        CallManager.getInstance().hangupForegroundResumeBackground(mBgCall);
        verify(mFgCall, times(1)).hangup();
        verify(mPhone, times(0)).switchHoldingAndActive();

        /* mock bgcall and fgcall from different phone */
        GsmCdmaPhone mPhoneHold = Mockito.mock(GsmCdmaPhone.class);
        doReturn(mPhoneHold).when(mBgCall).getPhone();
        CallManager.getInstance().hangupForegroundResumeBackground(mBgCall);
        verify(mFgCall, times(2)).hangup();
        /* always hangup fgcall and both phone trigger swap */
        verify(mPhoneHold, times(1)).switchHoldingAndActive();
        verify(mPhone, times(1)).switchHoldingAndActive();
    }

    @SmallTest @Test
    public void testFgCallActiveDial() throws Exception {
        /* set Fg/Bg Call state to active, verify CallManager Logical */
+11 −11
Original line number Diff line number Diff line
@@ -120,18 +120,18 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
        }
    }

    private void imsCallMocking(final ImsCall mImsCall) throws Exception {
    private void imsCallMocking(final ImsCall imsCall) throws Exception {

        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                // trigger the listener on accept call
                if (mImsCallListener != null) {
                    mImsCallListener.onCallStarted(mImsCall);
                    mImsCallListener.onCallStarted(imsCall);
                }
                return null;
            }
        }).when(mImsCall).accept(anyInt());
        }).when(imsCall).accept(anyInt());

        doAnswer(new Answer<Void>() {
            @Override
@@ -139,12 +139,12 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
                // trigger the listener on reject call
                int reasonCode = (int) invocation.getArguments()[0];
                if (mImsCallListener != null) {
                    mImsCallListener.onCallStartFailed(mImsCall, new ImsReasonInfo(reasonCode, -1));
                    mImsCallListener.onCallTerminated(mImsCall, new ImsReasonInfo(reasonCode, -1));
                    mImsCallListener.onCallStartFailed(imsCall, new ImsReasonInfo(reasonCode, -1));
                    mImsCallListener.onCallTerminated(imsCall, new ImsReasonInfo(reasonCode, -1));
                }
                return null;
            }
        }).when(mImsCall).reject(anyInt());
        }).when(imsCall).reject(anyInt());

        doAnswer(new Answer<Void>() {
            @Override
@@ -152,23 +152,23 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
                // trigger the listener on reject call
                int reasonCode = (int) invocation.getArguments()[0];
                if (mImsCallListener != null) {
                    mImsCallListener.onCallTerminated(mImsCall, new ImsReasonInfo(reasonCode, -1));
                    mImsCallListener.onCallTerminated(imsCall, new ImsReasonInfo(reasonCode, -1));
                }
                return null;
            }
        }).when(mImsCall).terminate(anyInt());
        }).when(imsCall).terminate(anyInt());

        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                if (mImsCallListener != null) {
                    mImsCallListener.onCallHeld(mImsCall);
                    mImsCallListener.onCallHeld(imsCall);
                }
                return null;
            }
        }).when(mImsCall).hold();
        }).when(imsCall).hold();

        mImsCall.attachSession(mImsCallSession);
        imsCall.attachSession(mImsCallSession);
    }

    @Before
Loading