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

Commit 2b3650da authored by Hunsuk Choi's avatar Hunsuk Choi Committed by Android (Google) Code Review
Browse files

Merge "Clear IMS call information when SRVCC has completed"

parents 1ea1daf0 6e63c130
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -78,6 +78,11 @@ public class ImsCallInfo {
        return changed;
    }

    /** Called when clearing orphaned connection. */
    public void onDisconnect() {
        mState = Call.State.DISCONNECTED;
    }

    /** @return the call index. */
    public int getIndex() {
        return mIndex;
+60 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.Phone;
import com.android.telephony.Rlog;

import java.util.ArrayList;
import java.util.Collection;
@@ -39,6 +40,8 @@ import java.util.Map;
 * Contains the state of all IMS calls.
 */
public class ImsCallInfoTracker {
    private static final String LOG_TAG = "ImsCallInfoTracker";
    private static final boolean DBG = false;

    private final Phone mPhone;
    private final List<ImsCallInfo> mQueue = new ArrayList<>();
@@ -56,6 +59,8 @@ public class ImsCallInfoTracker {
     * @param c The instance of {@link ImsPhoneConnection}.
     */
    public void addImsCallStatus(@NonNull ImsPhoneConnection c) {
        if (DBG) Rlog.d(LOG_TAG, "addImsCallStatus");

        synchronized (mImsCallInfo) {
            if (mQueue.isEmpty()) {
                mQueue.add(new ImsCallInfo(mNextIndex++));
@@ -69,6 +74,8 @@ public class ImsCallInfoTracker {
            mImsCallInfo.put(c, imsCallInfo);

            notifyImsCallStatus();

            if (DBG) dump();
        }
    }

@@ -90,16 +97,26 @@ public class ImsCallInfoTracker {
     */
    public void updateImsCallStatus(@NonNull ImsPhoneConnection c,
            boolean holdReceived, boolean resumeReceived) {
        if (DBG) {
            Rlog.d(LOG_TAG, "updateImsCallStatus holdReceived=" + holdReceived
                    + ", resumeReceived=" + resumeReceived);
        }

        synchronized (mImsCallInfo) {
            ImsCallInfo info = mImsCallInfo.get(c);

            if (info == null) {
                // This happens when the user tries to hangup the call after handover has completed.
                return;
            }

            boolean changed = info.update(c, holdReceived, resumeReceived);

            if (changed) notifyImsCallStatus();

            Call.State state = c.getState();

            if (DBG) Rlog.d(LOG_TAG, "updateImsCallStatus state=" + state);
            // Call is disconnected. There are 2 cases in disconnected state:
            // if silent redial, state == IDLE, otherwise, state == DISCONNECTED.
            if (state == DISCONNECTED || state == IDLE) {
@@ -113,6 +130,42 @@ public class ImsCallInfoTracker {
                    mNextIndex--;
                }
            }

            if (DBG) dump();
        }
    }

    /** Clears all orphaned IMS call information. */
    public void clearAllOrphanedConnections() {
        if (DBG) Rlog.d(LOG_TAG, "clearAllOrphanedConnections");

        Collection<ImsCallInfo> infos = mImsCallInfo.values();
        infos.stream().forEach(info -> { info.onDisconnect(); });
        notifyImsCallStatus();
        clearAllCallInfo();

        if (DBG) dump();
    }

    /** Notifies that SRVCC has completed. */
    public void notifySrvccCompleted() {
        if (DBG) Rlog.d(LOG_TAG, "notifySrvccCompleted");

        clearAllCallInfo();
        notifyImsCallStatus();

        if (DBG) dump();
    }

    private void clearAllCallInfo() {
        try {
            Collection<ImsCallInfo> infos = mImsCallInfo.values();
            infos.stream().forEach(info -> { info.reset(); });
            mImsCallInfo.clear();
            mQueue.clear();
            mNextIndex = 1;
        } catch (UnsupportedOperationException e) {
            Rlog.e(LOG_TAG, "e=" + e);
        }
    }

@@ -142,4 +195,11 @@ public class ImsCallInfoTracker {
            }
        });
    }

    private void dump() {
        Collection<ImsCallInfo> infos = mImsCallInfo.values();
        ArrayList<ImsCallInfo> imsCallInfo = new ArrayList<ImsCallInfo>(infos);
        sort(imsCallInfo);
        Rlog.d(LOG_TAG, "imsCallInfos=" + imsCallInfo);
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -1479,6 +1479,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        // above. Remove all references to it.
        mPendingMO = null;
        updatePhoneState();
        mImsCallInfoTracker.clearAllOrphanedConnections();
    }

    /**
@@ -4658,6 +4659,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
                transferHandoverConnections(mBackgroundCall);
                transferHandoverConnections(mRingingCall);
                updatePhoneState();
                mImsCallInfoTracker.notifySrvccCompleted();
                break;

            case TelephonyManager.SRVCC_STATE_HANDOVER_FAILED:
+54 −0
Original line number Diff line number Diff line
@@ -363,6 +363,60 @@ public class ImsCallInfoTrackerTest extends TelephonyTest {
        assertEquals(2, imsCallInfos.get(1).getIndex());
    }

    @Test
    public void testSrvccCompleted() throws Exception {
        ArgumentCaptor<List<ImsCallInfo>> captor = ArgumentCaptor.forClass(List.class);

        ImsPhoneConnection c = getConnection(Call.State.DIALING, false);
        mImsCallInfoTracker.addImsCallStatus(c);

        verify(mImsPhone, times(1)).updateImsCallStatus(captor.capture(), any());

        List<ImsCallInfo> imsCallInfos = captor.getValue();

        assertNotNull(imsCallInfos);
        assertEquals(1, imsCallInfos.size());

        mImsCallInfoTracker.notifySrvccCompleted();

        verify(mImsPhone, times(2)).updateImsCallStatus(captor.capture(), any());

        imsCallInfos = captor.getValue();

        assertNotNull(imsCallInfos);
        assertEquals(0, imsCallInfos.size());
    }

    @Test
    public void testClearAllOrphanedConnections() throws Exception {
        ArgumentCaptor<List<ImsCallInfo>> captor = ArgumentCaptor.forClass(List.class);

        ImsPhoneConnection c = getConnection(Call.State.DIALING, false);
        mImsCallInfoTracker.addImsCallStatus(c);

        verify(mImsPhone, times(1)).updateImsCallStatus(captor.capture(), any());

        List<ImsCallInfo> imsCallInfos = captor.getValue();

        assertNotNull(imsCallInfos);
        assertEquals(1, imsCallInfos.size());

        mImsCallInfoTracker.clearAllOrphanedConnections();

        verify(mImsPhone, times(2)).updateImsCallStatus(captor.capture(), any());

        imsCallInfos = captor.getValue();

        assertNotNull(imsCallInfos);
        assertEquals(1, imsCallInfos.size());

        ImsCallInfo info = imsCallInfos.get(0);

        assertNotNull(info);
        assertEquals(1, info.getIndex());
        assertEquals(Call.State.IDLE, info.getCallState());
    }

    private ImsPhoneConnection getConnection(Call.State state, boolean isEmergency) {
        ImsPhoneConnection c = mock(ImsPhoneConnection.class);
        doReturn(isEmergency).when(c).isEmergencyCall();
+35 −0
Original line number Diff line number Diff line
@@ -2464,6 +2464,41 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
        verify(mImsPhone, times(7)).updateImsCallStatus(any(), any());
    }

    @Test
    public void testUpdateImsCallStatusSrvccCompleted() throws Exception {
        // Incoming call
        setupRingingConnection();

        verify(mImsPhone, times(1)).updateImsCallStatus(any(), any());

        // no interaction when SRVCC has started, failed, or canceled.
        mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_STARTED);

        verify(mImsPhone, times(1)).updateImsCallStatus(any(), any());

        mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_FAILED);

        verify(mImsPhone, times(1)).updateImsCallStatus(any(), any());

        mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_CANCELED);

        verify(mImsPhone, times(1)).updateImsCallStatus(any(), any());

        // interaction when SRVCC has completed
        mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_COMPLETED);

        verify(mImsPhone, times(2)).updateImsCallStatus(any(), any());
    }

    @Test
    public void testClearAllOrphanedConnectionInfo() throws Exception {
        verify(mImsPhone, times(0)).updateImsCallStatus(any(), any());

        mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED);

        verify(mImsPhone, times(1)).updateImsCallStatus(any(), any());
    }

    /** Verifies that the request from ImsService is passed to ImsPhone as expected. */
    @Test
    @SmallTest