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

Commit 97cb01ac authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 8741289 from 1da1f284 to tm-qpr1-release

Change-Id: I8b685901f0242927b188b8dd90aa1fa2c9dc4943
parents ac69fc05 1da1f284
Loading
Loading
Loading
Loading
+23 −23
Original line number Diff line number Diff line
@@ -52,7 +52,6 @@ import com.android.internal.telephony.ExponentialBackoff;
import com.android.internal.telephony.util.TelephonyUtils;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -452,19 +451,24 @@ public class ImsServiceController {
                    SparseIntArray  slotIdToSubIdMap) throws RemoteException {
        sanitizeFeatureConfig(newImsFeatures);
        synchronized (mLock) {
            HashSet<Integer> slotIDs =  new HashSet<>();
            slotIDs.addAll(newImsFeatures.stream().map(e -> e.slotId).collect(Collectors.toSet()));
            ArrayList<Integer> changedSubIds = new ArrayList<Integer>();
            HashSet<Integer> slotIDs = newImsFeatures.stream().map(e -> e.slotId).collect(
                    Collectors.toCollection(HashSet::new));
            // detect which subIds have changed on a per-slot basis
            SparseIntArray changedSubIds = new SparseIntArray(slotIDs.size());
            for (Integer slotID : slotIDs) {
                if (mSlotIdToSubIdMap.get(slotID, PLACEHOLDER_SUBSCRIPTION_ID_BASE)
                        != slotIdToSubIdMap.get(slotID)) {
                    changedSubIds.add(slotIdToSubIdMap.get(slotID));
                    mLocalLog.log("changed sub IDs: " + changedSubIds);
                    Log.i(LOG_TAG, "changed sub IDs: " + changedSubIds);
                int oldSubId = mSlotIdToSubIdMap.get(slotID, PLACEHOLDER_SUBSCRIPTION_ID_BASE);
                int newSubId = slotIdToSubIdMap.get(slotID);
                if (oldSubId != newSubId) {
                    changedSubIds.put(slotID, newSubId);
                    mLocalLog.log("subId changed for slot: " + slotID + ", " + oldSubId + " -> "
                            + newSubId);
                    Log.i(LOG_TAG, "subId changed for slot: " + slotID + ", " + oldSubId + " -> "
                            + newSubId);
                }
            }
            mSlotIdToSubIdMap = slotIdToSubIdMap;
            if (mImsFeatures.equals(newImsFeatures) && !isSubIdChanged(changedSubIds)) {
            // no change, return early.
            if (mImsFeatures.equals(newImsFeatures) && changedSubIds.size() == 0) {
                return;
            }
            mLocalLog.log("Features (" + mImsFeatures + "->" + newImsFeatures + ")");
@@ -496,22 +500,22 @@ public class ImsServiceController {
                        new HashSet<>(mImsFeatures);
                unchangedFeatures.removeAll(oldFeatures);
                unchangedFeatures.removeAll(newFeatures);
                // ensure remove and add unchanged features that have a slot ID associated with
                // the new subscription ID.
                if (isSubIdChanged(changedSubIds)) {
                    for (Integer changedSubId : changedSubIds) {
                        int slotId = mSlotIdToSubIdMap.indexOfValue(changedSubId);
                // Go through ImsFeatures whose associated subId have changed and recreate them.
                if (changedSubIds.size() > 0) {
                    for (int slotId : changedSubIds.copyKeys()) {
                        int subId = changedSubIds.get(slotId,
                                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
                        HashSet<ImsFeatureConfiguration.FeatureSlotPair>
                                removeAddFeatures = new HashSet<>();
                        removeAddFeatures.addAll(unchangedFeatures.stream()
                                .filter(e -> e.slotId == slotId).collect(Collectors.toSet()));
                                removeAddFeatures = unchangedFeatures.stream()
                                .filter(e -> e.slotId == slotId).collect(
                                        Collectors.toCollection(HashSet::new));
                        for (ImsFeatureConfiguration.FeatureSlotPair i : removeAddFeatures) {
                            removeImsServiceFeature(i, true);
                        }
                        for (ImsFeatureConfiguration.FeatureSlotPair i : removeAddFeatures) {
                            long caps = modifyCapabiltiesForSlot(mImsFeatures, i.slotId,
                                    mServiceCapabilities);
                            addImsServiceFeature(i, caps, changedSubId);
                            addImsServiceFeature(i, caps, subId);
                        }
                        unchangedFeatures.removeAll(removeAddFeatures);
                    }
@@ -919,10 +923,6 @@ public class ImsServiceController {
        AnomalyReporter.reportAnomaly(mAnomalyUUID, message);
    }

    private boolean isSubIdChanged(ArrayList<Integer> changedSubIds) {
        return !changedSubIds.isEmpty();
    }

    @Override
    public String toString() {
        synchronized (mLock) {
+15 −4
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ import android.telephony.TelephonyLocalConnection;
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsCallSession;
import android.telephony.ims.ImsConferenceState;
import android.telephony.ims.ImsMmTelManager;
import android.telephony.ims.ImsReasonInfo;
@@ -2798,7 +2799,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {

    private void maybeSetVideoCallProvider(ImsPhoneConnection conn, ImsCall imsCall) {
        android.telecom.Connection.VideoProvider connVideoProvider = conn.getVideoProvider();
        if (connVideoProvider != null || imsCall.getCallSession().getVideoCallProvider() == null) {
        ImsCallSession callSession = imsCall.getCallSession(); 
        if (connVideoProvider != null || callSession == null
            || callSession.getVideoCallProvider() == null) {
            return;
        }

@@ -3292,12 +3295,20 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {

                } else if (conn.isIncoming() && conn.getConnectTime() == 0
                        && cause != DisconnectCause.ANSWERED_ELSEWHERE) {

                    if (conn.getDisconnectCause() == DisconnectCause.LOCAL) {
                    // Two cases where the call is declared as rejected.
                    // 1. The disconnect was initiated by the user.  I.e. the connection's
                    // disconnect cause is LOCAL at this point.
                    // 2. The network provided disconnect cause is INCOMING_REJECTED.  This will be
                    // the case for ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE and
                    // ImsReasonInfo.CODE_REJECTED_ELSEWHERE.
                    if (conn.getDisconnectCause() == DisconnectCause.LOCAL
                            || cause == DisconnectCause.INCOMING_REJECTED) {
                        // If the user initiated a disconnect of this connection, then we will treat
                        // this is a rejected call.
                        // Note; the record the fact that this is a local disconnect in
                        // Note; we record the fact that this is a local disconnect in
                        // ImsPhoneConnection#onHangupLocal
                        // Alternatively, the network can specify INCOMING_REJECTED as a result of
                        // remote reject on another device; we'll still treat as rejected.
                        cause = DisconnectCause.INCOMING_REJECTED;
                    } else {
                        // Otherwise in all other cases consider it missed.
+62 −0
Original line number Diff line number Diff line
@@ -381,6 +381,68 @@ public class ImsServiceControllerTest extends ImsTestBase {
        validateMmTelFeatureContainerExists(SLOT_1);
    }

    /**
     * Ensures ImsServiceController correctly removes the existing MmTelFeature and creates an
     * emergency only MmTelFeature when slot 0 has no subscription and the sim card is removed for
     * slot 1.
     */
    @SmallTest
    @Test
    public void testCallChangeWithNoNewFeaturesWithSlot1SubIdChanged()
            throws RemoteException {
        HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
                ImsFeature.FEATURE_EMERGENCY_MMTEL));
        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
                ImsFeature.FEATURE_MMTEL));
        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_1,
                ImsFeature.FEATURE_EMERGENCY_MMTEL));
        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_1,
                ImsFeature.FEATURE_MMTEL));
        SparseIntArray slotIdToSubIdMap = new SparseIntArray();
        // invalid subid in slot 0
        slotIdToSubIdMap.put(SLOT_0, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
        // valid subId in slot 1
        slotIdToSubIdMap.put(SLOT_1, SUB_3);
        bindAndConnectService(testFeatures, slotIdToSubIdMap.clone());
        verify(mMockServiceControllerBinder).createEmergencyOnlyMmTelFeature(SLOT_0);
        verify(mMockServiceControllerBinder).addFeatureStatusCallback(eq(SLOT_0),
                eq(ImsFeature.FEATURE_MMTEL), any());
        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
                eq(mTestImsServiceController));
        verify(mMockServiceControllerBinder).createMmTelFeature(SLOT_1, SUB_3);
        verify(mMockServiceControllerBinder).addFeatureStatusCallback(eq(SLOT_1),
                eq(ImsFeature.FEATURE_MMTEL), any());
        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_1), eq(ImsFeature.FEATURE_MMTEL),
                eq(mTestImsServiceController));
        validateMmTelFeatureContainerExistsWithEmergency(SLOT_0);
        validateMmTelFeatureContainerExistsWithEmergency(SLOT_1);

        slotIdToSubIdMap.put(SLOT_0, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
        slotIdToSubIdMap.put(SLOT_1, SubscriptionManager.INVALID_SUBSCRIPTION_ID);

        // ensure only slot 1 gets replaced with emergency only MmTelFeature.
        mTestImsServiceController.changeImsServiceFeatures(testFeatures,
                slotIdToSubIdMap.clone());
        verify(mMockServiceControllerBinder).removeImsFeature(eq(SLOT_1),
                eq(ImsFeature.FEATURE_MMTEL), eq(true));
        verify(mMockServiceControllerBinder).removeFeatureStatusCallback(eq(SLOT_1),
                eq(ImsFeature.FEATURE_MMTEL), any());
        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_1), eq(ImsFeature.FEATURE_MMTEL),
                eq(mTestImsServiceController));

        verify(mMockServiceControllerBinder).createEmergencyOnlyMmTelFeature(SLOT_1);
        verify(mMockServiceControllerBinder, times(2)).addFeatureStatusCallback(eq(SLOT_1),
                eq(ImsFeature.FEATURE_MMTEL), any());
        verify(mMockCallbacks, times(2)).imsServiceFeatureCreated(eq(SLOT_1),
                eq(ImsFeature.FEATURE_MMTEL), eq(mTestImsServiceController));
        validateMmTelFeatureContainerExistsWithEmergency(SLOT_0);
        validateMmTelFeatureContainerExistsWithEmergency(SLOT_1);

        // this should not have been called again since it did not change (times = 1)
        verify(mMockServiceControllerBinder, times(1)).createEmergencyOnlyMmTelFeature(SLOT_0);
    }

    /**
     * Tests ImsServiceController keeps SIP delegate creation flags if MMTEL and RCS are supported.
     */
+34 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -144,6 +145,39 @@ public class ImsCallTest extends TelephonyTest {
        assertTrue(imsCall.wasVideoCall());
    }

    @Test
    @SmallTest
    public void testCloseImsCallRtt() throws Exception {
        ImsCallSession mockSession = mock(ImsCallSession.class);
        ImsStreamMediaProfile streamProfile = new ImsStreamMediaProfile(
                ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB,
                ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE,
                ImsStreamMediaProfile.VIDEO_QUALITY_NONE,
                ImsStreamMediaProfile.DIRECTION_INACTIVE,
                // Full RTT mode
                ImsStreamMediaProfile.RTT_MODE_FULL);
        ImsCallProfile profile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
                ImsCallProfile.CALL_TYPE_VOICE, null /*extras*/, streamProfile);
        profile.mCallType = ImsCallProfile.CALL_TYPE_VOICE;
        ImsCall imsCall = new ImsCall(mContext, profile);
        imsCall.attachSession(mockSession);

        imsCall.sendRttMessage("test");
        verify(mockSession).sendRttMessage("test");

        //called by ImsPhoneCallTracker when the call is terminated
        imsCall.close();

        try {
            // Ensure RTT cases are handled gracefully.
            imsCall.sendRttMessage("test");
            imsCall.sendRttModifyRequest(true);
            imsCall.sendRttModifyResponse(true);
        } catch (Exception e) {
            fail("Unexpected exception: " + e);
        }
    }

    @Test
    @SmallTest
    public void testSetWifi() {
+34 −0
Original line number Diff line number Diff line
@@ -508,6 +508,24 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
        assertEquals(DisconnectCause.INCOMING_REJECTED, connection.getDisconnectCause());
    }

    @Test
    @SmallTest
    public void testRejectedElsewhereIsRejected() {
        ImsPhoneConnection connection = setupRingingConnection();
        mImsCallListener.onCallTerminated(connection.getImsCall(),
                new ImsReasonInfo(ImsReasonInfo.CODE_REJECTED_ELSEWHERE, 0));
        assertEquals(DisconnectCause.INCOMING_REJECTED, connection.getDisconnectCause());
    }

    @Test
    @SmallTest
    public void testRemoteCallDeclineIsRejected() {
        ImsPhoneConnection connection = setupRingingConnection();
        mImsCallListener.onCallTerminated(connection.getImsCall(),
                new ImsReasonInfo(ImsReasonInfo.CODE_REMOTE_CALL_DECLINE, 0));
        assertEquals(DisconnectCause.INCOMING_REJECTED, connection.getDisconnectCause());
    }

    private ImsPhoneConnection setupRingingConnection() {
        mImsCallProfile.setCallerNumberVerificationStatus(
                ImsCallProfile.VERIFICATION_STATUS_PASSED);
@@ -1860,6 +1878,22 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
        assertEquals(Call.State.IDLE, mCTUT.mForegroundCall.getState());
    }

    @Test
    @SmallTest
    public void testCallSessionUpdatedAfterSrvccCompleted() throws RemoteException {
        startOutgoingCall();

        // Move the connection to the handover state.
        mCTUT.notifySrvccState(Call.SrvccState.COMPLETED);

        try {
            // When trigger CallSessionUpdated after Srvcc completes, checking no exception.
            mImsCallListener.onCallUpdated(mSecondImsCall);
        } catch (Exception ex) {
            Assert.fail("unexpected exception thrown" + ex.getMessage());
        }
    }

    private void sendCarrierConfigChanged() {
        Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
        intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId());