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

Commit 281a79f1 authored by Tyler Gunn's avatar Tyler Gunn Committed by Automerger Merge Worker
Browse files

Merge "Pipe through received DTMF tone pathway and RTP send/receive." am: 378d9740

Original change: https://android-review.googlesource.com/c/platform/frameworks/opt/telephony/+/1467337

Change-Id: I19111e4e8f81061e4c95f743035da9dd73baeaa2
parents 365fe692 378d9740
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.internal.telephony;

import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.Uri;
import android.os.Build;
@@ -25,6 +26,7 @@ import android.telephony.DisconnectCause;
import android.telephony.ServiceState;
import android.telephony.ServiceState.RilRadioTechnology;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.RtpHeaderExtension;
import android.util.Log;

import com.android.ims.internal.ConferenceParticipant;
@@ -119,6 +121,18 @@ public abstract class Connection {
        public void onRttTerminated();
        public void onOriginalConnectionReplaced(Connection newConnection);
        public void onIsNetworkEmergencyCallChanged(boolean isEmergencyCall);

        /**
         * Indicates a DTMF digit has been received from the network.
         * @param digit The DTMF digit.
         */
        public void onReceivedDtmfDigit(char digit);

        /**
         * Indicates data from an RTP header extension has been received from the network.
         * @param extensionData The extension data.
         */
        public void onReceivedRtpHeaderExtensions(@NonNull Set<RtpHeaderExtension> extensionData);
    }

    /**
@@ -168,6 +182,10 @@ public abstract class Connection {
        public void onOriginalConnectionReplaced(Connection newConnection) {}
        @Override
        public void onIsNetworkEmergencyCallChanged(boolean isEmergencyCall) {}
        @Override
        public void onReceivedDtmfDigit(char digit) {}
        @Override
        public void onReceivedRtpHeaderExtensions(@NonNull Set<RtpHeaderExtension> extensionData) {}
    }

    public static final int AUDIO_QUALITY_STANDARD = 1;
@@ -1427,4 +1445,24 @@ public abstract class Connection {
            @android.telecom.Connection.VerificationStatus int verificationStatus) {
        mNumberVerificationStatus = verificationStatus;
    }

    /**
     * Called to report a DTMF digit received from the network.
     * @param digit the received digit.
     */
    public void receivedDtmfDigit(char digit) {
        for (Listener l : mListeners) {
            l.onReceivedDtmfDigit(digit);
        }
    }

    /**
     * Called to report RTP header extensions received from the network.
     * @param extensionData the received extension data.
     */
    public void receivedRtpHeaderExtensions(@NonNull Set<RtpHeaderExtension> extensionData) {
        for (Listener l : mListeners) {
            l.onReceivedRtpHeaderExtensions(extensionData);
        }
    }
}
+43 −21
Original line number Diff line number Diff line
@@ -124,6 +124,14 @@ public class TelephonyTester {
    private static final String ACTION_TEST_IMS_E_CALL =
            "com.android.internal.telephony.TestImsECall";

    /**
     * Test-only intent used to trigger signalling that an IMS call received a DTMF tone.
     */
    private static final String ACTION_TEST_RECEIVE_DTMF =
            "com.android.internal.telephony.TestReceiveDtmf";

    private static final String EXTRA_DIGIT = "digit";

    /**
     * Test-only intent used to trigger a change to the current call's phone number.
     * Use the {@link #EXTRA_NUMBER} extra to specify the new phone number.
@@ -197,6 +205,9 @@ public class TelephonyTester {
                } else if (action.equals(ACTION_TEST_IMS_E_CALL)) {
                    log("handle test IMS ecall intent");
                    testImsECall();
                } else if (action.equals(ACTION_TEST_RECEIVE_DTMF)) {
                    log("handle test DTMF intent");
                    testImsReceiveDtmf(intent);
                } else if (action.equals(ACTION_TEST_CHANGE_NUMBER)) {
                    log("handle test change number intent");
                    testChangeNumber(intent);
@@ -229,6 +240,7 @@ public class TelephonyTester {
                filter.addAction(ACTION_TEST_HANDOVER_FAIL);
                filter.addAction(ACTION_TEST_SUPP_SRVC_NOTIFICATION);
                filter.addAction(ACTION_TEST_IMS_E_CALL);
                filter.addAction(ACTION_TEST_RECEIVE_DTMF);
                mImsExternalCallStates = new ArrayList<ImsExternalCallState>();
            }

@@ -262,17 +274,7 @@ public class TelephonyTester {

    private void handleHandoverFailedIntent() {
        // Attempt to get the active IMS call
        ImsPhone imsPhone = (ImsPhone) mPhone;
        if (imsPhone == null) {
            return;
        }

        ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall();
        if (imsPhoneCall == null) {
            return;
        }

        ImsCall imsCall = imsPhoneCall.getImsCall();
        ImsCall imsCall = getImsCall();
        if (imsCall == null) {
            return;
        }
@@ -491,30 +493,50 @@ public class TelephonyTester {

    void testImsECall() {
        // Attempt to get the active IMS call before parsing the test XML file.
        ImsCall imsCall = getImsCall();
        if (imsCall == null) return;

        ImsCallProfile callProfile = imsCall.getCallProfile();
        Bundle extras = callProfile.getCallExtras();
        if (extras == null) {
            extras = new Bundle();
        }
        extras.putBoolean(ImsCallProfile.EXTRA_EMERGENCY_CALL, true);
        callProfile.mCallExtras = extras;
        imsCall.getImsCallSessionListenerProxy().callSessionUpdated(imsCall.getSession(),
                callProfile);
    }

    private ImsCall getImsCall() {
        ImsPhone imsPhone = (ImsPhone) mPhone;
        if (imsPhone == null) {
            return;
            return null;
        }

        ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall();
        if (imsPhoneCall == null) {
            return;
            return null;
        }

        ImsCall imsCall = imsPhoneCall.getImsCall();
        if (imsCall == null) {
            return null;
        }
        return imsCall;
    }

    void testImsReceiveDtmf(Intent intent) {
        if (!intent.hasExtra(EXTRA_DIGIT)) {
            return;
        }
        char digit = intent.getStringExtra(EXTRA_DIGIT).charAt(0);

        ImsCallProfile callProfile = imsCall.getCallProfile();
        Bundle extras = callProfile.getCallExtras();
        if (extras == null) {
            extras = new Bundle();
        ImsCall imsCall = getImsCall();
        if (imsCall == null) {
            return;
        }
        extras.putBoolean(ImsCallProfile.EXTRA_EMERGENCY_CALL, true);
        callProfile.mCallExtras = extras;
        imsCall.getImsCallSessionListenerProxy().callSessionUpdated(imsCall.getSession(),
                callProfile);

        imsCall.getImsCallSessionListenerProxy().callSessionDtmfReceived(digit);
    }

    void testChangeNumber(Intent intent) {
+27 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsStreamMediaProfile;
import android.telephony.ims.ImsSuppServiceNotification;
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.RtpHeaderExtension;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -124,6 +125,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
@@ -3576,6 +3578,15 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
            mPhone.notifySuppServiceFailed(Phone.SuppService.TRANSFER);
        }

        @Override
        public void onCallSessionDtmfReceived(ImsCall imsCall, char digit) {
            log("onCallSessionDtmfReceived digit=" + digit);
            ImsPhoneConnection conn = findConnection(imsCall);
            if (conn != null) {
                conn.receivedDtmfDigit(digit);
            }
        }

        /**
         * Handles a change to the multiparty state for an {@code ImsCall}.  Notifies the associated
         * {@link ImsPhoneConnection} of the change.
@@ -3610,6 +3621,22 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
            cqm.saveCallQuality(callQuality);
            mCallQualityMetrics.put(callId, cqm);
        }

        /**
         * Handles reception of RTP header extension data from the network.
         * @param imsCall The ImsCall the data was received on.
         * @param rtpHeaderExtensionData The RTP extension data received.
         */
        @Override
        public void onCallSessionRtpHeaderExtensionsReceived(ImsCall imsCall,
                @NonNull Set<RtpHeaderExtension> rtpHeaderExtensionData) {
            log("onCallSessionRtpHeaderExtensionsReceived numExtensions="
                    + rtpHeaderExtensionData.size());
            ImsPhoneConnection conn = findConnection(imsCall);
            if (conn != null) {
                conn.receivedRtpHeaderExtensions(rtpHeaderExtensionData);
            }
        }
    };

    /**
+56 −0
Original line number Diff line number Diff line
@@ -16,21 +16,29 @@

package android.telephony.ims;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.telephony.ims.aidl.IImsCallSessionListener;
import android.util.ArraySet;

import androidx.test.runner.AndroidJUnit4;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.List;

@RunWith(AndroidJUnit4.class)
public class ImsCallSessionListenerTests {

@@ -75,4 +83,52 @@ public class ImsCallSessionListenerTests {
                eq(TelephonyManager.NETWORK_TYPE_IWLAN), eq(imsReasonInfo));
    }

    @Test
    public void testCallSessionDtmfReceived() throws Exception {
        ImsCallSessionListener mTestListener = new ImsCallSessionListener(mMockListener);
        mTestListener.callSessionDtmfReceived('A');
        mTestListener.callSessionDtmfReceived('a');
        verify(mMockListener, times(2)).callSessionDtmfReceived(eq('A'));

        mTestListener.callSessionDtmfReceived('B');
        mTestListener.callSessionDtmfReceived('b');
        verify(mMockListener, times(2)).callSessionDtmfReceived(eq('B'));

        mTestListener.callSessionDtmfReceived('0');
        verify(mMockListener, times(1)).callSessionDtmfReceived(eq('0'));

        mTestListener.callSessionDtmfReceived('*');
        verify(mMockListener, times(1)).callSessionDtmfReceived(eq('*'));
        mTestListener.callSessionDtmfReceived('#');
        verify(mMockListener, times(1)).callSessionDtmfReceived(eq('#'));

        try {
            mTestListener.callSessionDtmfReceived('P');
            fail("expected exception");
        } catch (IllegalArgumentException illegalArgumentException) {
            // expected
        }
    }

    @Test
    public void testCallSessionRtpExtensionHeadersReceived() throws Exception {
        ImsCallSessionListener mTestListener = new ImsCallSessionListener(mMockListener);
        ArraySet<RtpHeaderExtension> headers = new ArraySet<RtpHeaderExtension>();
        RtpHeaderExtension extension = new RtpHeaderExtension(1, new byte[1]);
        headers.add(extension);
        mTestListener.callSessionRtpHeaderExtensionsReceived(headers);
        final ArgumentCaptor<List<RtpHeaderExtension>> listCaptor =
                ArgumentCaptor.forClass((Class) List.class);
        verify(mMockListener).callSessionRtpHeaderExtensionsReceived(
                listCaptor.capture());
        assertEquals(1, listCaptor.getValue().size());
        assertEquals(extension.getLocalIdentifier(),
                listCaptor.getValue().get(0).getLocalIdentifier());
        try {
            mTestListener.callSessionRtpHeaderExtensionsReceived(null);
            fail("expected exception");
        } catch (NullPointerException npe) {
            // expected
        }
    }
}