CTS for media quality status notification

- CTS for MediaThreshold & MediaQualityStatusf
- CTS for end to end verification. (TelephonyCallback - ImsServie)
- CTS for setMediaThreshold, queryMediaThreshold in MmtelFeature API

Bug: 242934908
Test: atest CtsTelephonyTestCases
Change-Id: I847d9afe52ccf02293ce9f1cdd9621b017b4f04f
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingBase.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingBase.java
index 912714a..a613f2b 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingBase.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingBase.java
@@ -87,6 +87,9 @@
     public static final int LATCH_IS_ON_CALL_REMOTELY_HELD = 11;
     public static final int LATCH_IS_ON_CALL_REMOTELY_UNHELD = 12;
     public static final int LATCH_MAX = 13;
+    public static final int TEST_RTP_THRESHOLD_PACKET_LOSS_RATE = 47;
+    public static final int TEST_RTP_THRESHOLD_JITTER_MILLIS = 150;
+    public static final long TEST_RTP_THRESHOLD_INACTIVITY_TIME_MILLIS = 3000;
 
     protected static boolean sIsBound = false;
     protected static int sCounter = 5553639;
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java
index e9e99f6..5a125eb 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java
@@ -16,12 +16,14 @@
 
 package android.telephony.ims.cts;
 
-import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
+import android.annotation.NonNull;
+import android.app.UiAutomation;
 import android.content.Context;
 import android.media.AudioManager;
 import android.net.Uri;
@@ -29,10 +31,13 @@
 import android.telecom.Call;
 import android.telecom.PhoneAccount;
 import android.telecom.TelecomManager;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 import android.telephony.cts.InCallServiceStateValidator;
 import android.telephony.ims.ImsCallSessionListener;
+import android.telephony.ims.MediaQualityStatus;
 import android.telephony.ims.feature.MmTelFeature;
 import android.util.Log;
 
@@ -50,6 +55,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -1105,6 +1111,105 @@
         waitForUnboundService();
     }
 
+    @Test
+    public void testNotifyMediaCallStatusChanged() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        bindImsService();
+        mServiceCallBack = new ServiceCallBack();
+        InCallServiceStateValidator.setCallbacks(mServiceCallBack);
+
+        TelecomManager telecomManager = (TelecomManager) InstrumentationRegistry
+                .getInstrumentation().getContext().getSystemService(Context.TELECOM_SERVICE);
+
+        final Uri imsUri = Uri.fromParts(PhoneAccount.SCHEME_TEL, String.valueOf(++sCounter), null);
+        Bundle extras = new Bundle();
+
+        // Place outgoing call
+        telecomManager.placeCall(imsUri, extras);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_ADDED, WAIT_FOR_CALL_STATE));
+
+        Call call = getCall(mCurrentCallId);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DIALING, WAIT_FOR_CALL_STATE));
+
+        TestImsCallSessionImpl callSession = sServiceConnector.getCarrierService().getMmTelFeature()
+                .getImsCallsession();
+
+        isCallActive(call, callSession);
+        String callSessionId = callSession.getCallId();
+
+        LinkedBlockingQueue<MediaQualityStatus> queue = new LinkedBlockingQueue<>();
+        ImsCallingTest.TestTelephonyCallback testCb =
+                new ImsCallingTest.TestTelephonyCallback(queue);
+        TelephonyManager telephonyManager = getContext().getSystemService(TelephonyManager.class);
+
+        //test registration without permission
+        try {
+            telephonyManager.registerTelephonyCallback(getContext().getMainExecutor(), testCb);
+            fail("registerTelephonyCallback requires READ_PRECISE_PHONE_STATE permission.");
+        } catch (SecurityException e) {
+            //expected
+        }
+
+        final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            automan.adoptShellPermissionIdentity();
+            telephonyManager.registerTelephonyCallback(getContext().getMainExecutor(), testCb);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        //Expect to receive cached media quality status retrieved by #queryMediaQualityStatus.
+        MediaQualityStatus status = queue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertNotNull(status);
+        assertEquals(callSessionId, status.getCallSessionId());
+        assertEquals(MediaQualityStatus.MEDIA_SESSION_TYPE_AUDIO, status.getMediaSessionType());
+        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, status.getTransportType());
+        assertEquals(0, status.getRtpPacketLossRate());
+        assertEquals(0, status.getRtpJitterMillis());
+        assertEquals(0, status.getRtpInactivityMillis());
+
+        //Notify a new media quality status.
+        sServiceConnector.getCarrierService().getMmTelFeature()
+                .notifyMediaQualityStatusChanged(new MediaQualityStatus
+                        .Builder(callSessionId,
+                        MediaQualityStatus.MEDIA_SESSION_TYPE_AUDIO,
+                        AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                        .setRtpPacketLossRate(TEST_RTP_THRESHOLD_PACKET_LOSS_RATE)
+                        .setRtpJitterMillis(TEST_RTP_THRESHOLD_JITTER_MILLIS)
+                        .setRtpInactivityMillis(TEST_RTP_THRESHOLD_INACTIVITY_TIME_MILLIS).build());
+
+        status = queue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertNotNull(status);
+        assertEquals(callSessionId, status.getCallSessionId());
+        assertEquals(MediaQualityStatus.MEDIA_SESSION_TYPE_AUDIO, status.getMediaSessionType());
+        assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, status.getTransportType());
+        assertEquals(TEST_RTP_THRESHOLD_PACKET_LOSS_RATE, status.getRtpPacketLossRate());
+        assertEquals(TEST_RTP_THRESHOLD_JITTER_MILLIS, status.getRtpJitterMillis());
+        assertEquals(TEST_RTP_THRESHOLD_INACTIVITY_TIME_MILLIS, status.getRtpInactivityMillis());
+
+        call.disconnect();
+
+        assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DISCONNECTING, WAIT_FOR_CALL_STATE));
+        isCallDisconnected(call, callSession);
+        assertTrue(callingTestLatchCountdown(LATCH_IS_ON_CALL_REMOVED, WAIT_FOR_CALL_STATE));
+        waitForUnboundService();
+    }
+
+    private class TestTelephonyCallback extends TelephonyCallback
+            implements TelephonyCallback.MediaQualityStatusChangedListener {
+        LinkedBlockingQueue<MediaQualityStatus> mTestMediaQualityStatusQueue;
+        TestTelephonyCallback(LinkedBlockingQueue<MediaQualityStatus> queue) {
+            mTestMediaQualityStatusQueue = queue;
+        }
+        @Override
+        public void onMediaQualityStatusChanged(@NonNull MediaQualityStatus status) {
+            mTestMediaQualityStatusQueue.offer(status);
+        }
+    }
+
     void addConferenceCall(Call call1, Call call2) {
         InCallServiceStateValidator inCallService = mServiceCallBack.getService();
 
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
index ff63044..73a2c3d 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
@@ -27,6 +27,7 @@
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.fail;
@@ -59,6 +60,7 @@
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ImsRegistrationAttributes;
 import android.telephony.ims.ImsStateCallback;
+import android.telephony.ims.MediaThreshold;
 import android.telephony.ims.ProvisioningManager;
 import android.telephony.ims.RcsClientConfiguration;
 import android.telephony.ims.RcsContactUceCapability;
@@ -4663,6 +4665,43 @@
     }
 
     @Test
+    public void testSetMediaThreshold() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        sServiceConnector.setDeviceToDeviceCommunicationEnabled(true);
+        try {
+            PersistableBundle bundle = new PersistableBundle();
+            bundle.putInt(
+                    CarrierConfigManager.ImsVoice.KEY_VOICE_RTP_PACKET_LOSS_RATE_THRESHOLD_INT,
+                    10);
+            bundle.putLong(
+                    CarrierConfigManager
+                            .ImsVoice
+                            .KEY_VOICE_RTP_INACTIVITY_TIME_THRESHOLD_MILLIS_LONG, 5000);
+            bundle.putInt(
+                    CarrierConfigManager
+                            .ImsVoice.KEY_VOICE_RTP_JITTER_THRESHOLD_MILLIS_INT, 70);
+            overrideCarrierConfig(bundle);
+
+            triggerFrameworkConnectToCarrierImsService();
+
+            sServiceConnector.getCarrierService().getMmTelFeature()
+                    .getSetMediaThresholdLatch().await(5000, TimeUnit.MILLISECONDS);
+            MediaThreshold threshold =
+                    sServiceConnector.getCarrierService().getMmTelFeature().getSetMediaThreshold();
+
+            assertNotNull(threshold);
+            assertArrayEquals(new int[]{10}, threshold.getThresholdsRtpPacketLossRate());
+            assertArrayEquals(new int[]{70}, threshold.getThresholdsRtpJitterMillis());
+            assertArrayEquals(new long[]{5000}, threshold.getThresholdsRtpInactivityTimeMillis());
+        } finally {
+            sServiceConnector.setDeviceToDeviceCommunicationEnabled(false);
+            overrideCarrierConfig(null);
+        }
+    }
+
+    @Test
     public void testImsMmTelManagerImsStateCallback() throws Exception {
         if (!ImsUtils.shouldTestImsService()) {
             return;
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/MediaQualityStatusTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/MediaQualityStatusTest.java
new file mode 100644
index 0000000..2de3b2f
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/MediaQualityStatusTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.os.Parcel;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.ims.MediaQualityStatus;
+
+import org.junit.Test;
+
+public class MediaQualityStatusTest {
+
+    private static final String TEST_IMS_CALL_SESSION_ID = "test";
+    private static final int TEST_MEDIA_SESSION_TYPE = MediaQualityStatus.MEDIA_SESSION_TYPE_AUDIO;
+    private static final int TEST_TRANSPORT_TYPE = AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
+    private static final int THRESHOLD_PACKET_LOSS_RATE = 10;
+    private static final int THRESHOLD_JITTER_MILLIS = 100;
+    private static final long THRESHOLD_INACTIVITY_TIME_MILLIS = 7000;
+
+    @Test
+    public void testBuilderAndGetters() {
+        MediaQualityStatus status = new MediaQualityStatus.Builder(
+                TEST_IMS_CALL_SESSION_ID, TEST_MEDIA_SESSION_TYPE, TEST_TRANSPORT_TYPE)
+                .setRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setRtpInactivityMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+
+        assertEquals(TEST_IMS_CALL_SESSION_ID, status.getCallSessionId());
+        assertEquals(TEST_MEDIA_SESSION_TYPE, status.getMediaSessionType());
+        assertEquals(TEST_TRANSPORT_TYPE, status.getTransportType());
+        assertEquals(THRESHOLD_PACKET_LOSS_RATE, status.getRtpPacketLossRate());
+        assertEquals(THRESHOLD_JITTER_MILLIS, status.getRtpJitterMillis());
+        assertEquals(THRESHOLD_INACTIVITY_TIME_MILLIS, status.getRtpInactivityMillis());
+    }
+
+    @Test
+    public void testEquals() {
+        MediaQualityStatus status1 = new MediaQualityStatus.Builder(
+                TEST_IMS_CALL_SESSION_ID, TEST_MEDIA_SESSION_TYPE, TEST_TRANSPORT_TYPE)
+                .setRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setRtpInactivityMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+        MediaQualityStatus status2 = new MediaQualityStatus.Builder(
+                TEST_IMS_CALL_SESSION_ID, TEST_MEDIA_SESSION_TYPE, TEST_TRANSPORT_TYPE)
+                .setRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setRtpInactivityMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+
+        assertEquals(status1, status2);
+    }
+
+    @Test
+    public void testNotEquals() {
+        MediaQualityStatus status1 = new MediaQualityStatus.Builder(
+                TEST_IMS_CALL_SESSION_ID, TEST_MEDIA_SESSION_TYPE, TEST_TRANSPORT_TYPE)
+                .setRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setRtpInactivityMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+        MediaQualityStatus status2 = new MediaQualityStatus.Builder(
+                TEST_IMS_CALL_SESSION_ID + "TEST", TEST_MEDIA_SESSION_TYPE, TEST_TRANSPORT_TYPE)
+                .setRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setRtpInactivityMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+        assertNotEquals(status1, status2);
+
+        status2 = new MediaQualityStatus.Builder(
+                TEST_IMS_CALL_SESSION_ID, TEST_MEDIA_SESSION_TYPE + 1, TEST_TRANSPORT_TYPE)
+                .setRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setRtpInactivityMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+        assertNotEquals(status1, status2);
+
+        status2 = new MediaQualityStatus.Builder(
+                TEST_IMS_CALL_SESSION_ID, TEST_MEDIA_SESSION_TYPE, TEST_TRANSPORT_TYPE + 1)
+                .setRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setRtpInactivityMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+        assertNotEquals(status1, status2);
+
+        status2 = new MediaQualityStatus.Builder(
+                TEST_IMS_CALL_SESSION_ID, TEST_MEDIA_SESSION_TYPE, TEST_TRANSPORT_TYPE)
+                .setRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE + 10)
+                .setRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setRtpInactivityMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+        assertNotEquals(status1, status2);
+
+        status2 = new MediaQualityStatus.Builder(
+                TEST_IMS_CALL_SESSION_ID, TEST_MEDIA_SESSION_TYPE, TEST_TRANSPORT_TYPE)
+                .setRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setRtpJitterMillis(THRESHOLD_JITTER_MILLIS + 10)
+                .setRtpInactivityMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+        assertNotEquals(status1, status2);
+
+        status2 = new MediaQualityStatus.Builder(
+                TEST_IMS_CALL_SESSION_ID, TEST_MEDIA_SESSION_TYPE, TEST_TRANSPORT_TYPE)
+                .setRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setRtpInactivityMillis(THRESHOLD_INACTIVITY_TIME_MILLIS + 500)
+                .build();
+        assertNotEquals(status1, status2);
+    }
+
+    @Test
+    public void testParcel() {
+        MediaQualityStatus status = new MediaQualityStatus.Builder(
+                TEST_IMS_CALL_SESSION_ID, TEST_MEDIA_SESSION_TYPE, TEST_TRANSPORT_TYPE)
+                .setRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setRtpInactivityMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+
+        Parcel mediaQualityStatusParcel = Parcel.obtain();
+        status.writeToParcel(mediaQualityStatusParcel, 0);
+        mediaQualityStatusParcel.setDataPosition(0);
+
+        MediaQualityStatus postParcel =
+                MediaQualityStatus.CREATOR.createFromParcel(mediaQualityStatusParcel);
+        assertEquals(status, postParcel);
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/MediaThresholdTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/MediaThresholdTest.java
new file mode 100644
index 0000000..db892b0
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/MediaThresholdTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims.cts;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.os.Parcel;
+import android.telephony.ims.MediaThreshold;
+
+import org.junit.Test;
+
+public class MediaThresholdTest {
+
+    private static final int[] THRESHOLD_PACKET_LOSS_RATE = {10, 20};
+    private static final int[] THRESHOLD_JITTER_MILLIS = {100};
+    private static final long[] THRESHOLD_INACTIVITY_TIME_MILLIS = {3000, 7000};
+    private static final int[] THRESHOLD_PACKET_LOSS_RATE2 = {10, 30};
+    private static final int[] THRESHOLD_JITTER_MILLIS2 = {110};
+    private static final long[] THRESHOLD_INACTIVITY_TIME_MILLIS2 = {3700, 5700};
+    private static final int[] THRESHOLD_PACKET_LOSS_RATE3 = {10, 110};
+    private static final int[] THRESHOLD_JITTER_MILLIS3 = {-1, 100};
+    private static final long[] THRESHOLD_INACTIVITY_TIME_MILLIS3 = {-1, 3000, 5000, 60500};
+
+    @Test
+    public void testBuilderAndGetters() {
+        MediaThreshold status = new MediaThreshold.Builder()
+                .setThresholdsRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setThresholdsRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setThresholdsRtpInactivityTimeMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+
+        assertArrayEquals(THRESHOLD_PACKET_LOSS_RATE, status.getThresholdsRtpPacketLossRate());
+        assertArrayEquals(THRESHOLD_JITTER_MILLIS, status.getThresholdsRtpJitterMillis());
+        assertArrayEquals(
+                THRESHOLD_INACTIVITY_TIME_MILLIS, status.getThresholdsRtpInactivityTimeMillis());
+
+        status = new MediaThreshold.Builder()
+                .setThresholdsRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE3)
+                .setThresholdsRtpJitterMillis(THRESHOLD_JITTER_MILLIS3)
+                .setThresholdsRtpInactivityTimeMillis(THRESHOLD_INACTIVITY_TIME_MILLIS3)
+                .build();
+
+        assertArrayEquals(new int[]{10}, status.getThresholdsRtpPacketLossRate());
+        assertArrayEquals(new int[]{100}, status.getThresholdsRtpJitterMillis());
+        assertArrayEquals(new long[]{3000, 5000}, status.getThresholdsRtpInactivityTimeMillis());
+    }
+
+    @Test
+    public void testEquals() {
+        MediaThreshold status1 = new MediaThreshold.Builder()
+                .setThresholdsRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setThresholdsRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setThresholdsRtpInactivityTimeMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+        MediaThreshold status2 = new MediaThreshold.Builder()
+                .setThresholdsRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setThresholdsRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setThresholdsRtpInactivityTimeMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+
+        assertEquals(status1, status2);
+    }
+
+    @Test
+    public void testNotEquals() {
+        MediaThreshold status1 = new MediaThreshold.Builder()
+                .setThresholdsRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setThresholdsRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setThresholdsRtpInactivityTimeMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+        MediaThreshold status2 = new MediaThreshold.Builder()
+                .setThresholdsRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE2)
+                .setThresholdsRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setThresholdsRtpInactivityTimeMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+        assertNotEquals(status1, status2);
+
+        status2 = new MediaThreshold.Builder()
+                .setThresholdsRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setThresholdsRtpJitterMillis(THRESHOLD_JITTER_MILLIS2)
+                .setThresholdsRtpInactivityTimeMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+        assertNotEquals(status1, status2);
+
+        status2 = new MediaThreshold.Builder()
+                .setThresholdsRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setThresholdsRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setThresholdsRtpInactivityTimeMillis(THRESHOLD_INACTIVITY_TIME_MILLIS2)
+                .build();
+        assertNotEquals(status1, status2);
+    }
+
+    @Test
+    public void testParcel() {
+        MediaThreshold status = new MediaThreshold.Builder()
+                .setThresholdsRtpPacketLossRate(THRESHOLD_PACKET_LOSS_RATE)
+                .setThresholdsRtpJitterMillis(THRESHOLD_JITTER_MILLIS)
+                .setThresholdsRtpInactivityTimeMillis(THRESHOLD_INACTIVITY_TIME_MILLIS)
+                .build();
+
+        Parcel thresholdParcel = Parcel.obtain();
+        status.writeToParcel(thresholdParcel, 0);
+        thresholdParcel.setDataPosition(0);
+
+        MediaThreshold postParcel = MediaThreshold.CREATOR.createFromParcel(thresholdParcel);
+        assertEquals(status, postParcel);
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java
index c615863..45dfa27 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java
@@ -17,10 +17,13 @@
 package android.telephony.ims.cts;
 
 import android.os.Bundle;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsCallSessionListener;
 import android.telephony.ims.ImsStreamMediaProfile;
+import android.telephony.ims.MediaQualityStatus;
+import android.telephony.ims.MediaThreshold;
 import android.telephony.ims.RtpHeaderExtensionType;
 import android.telephony.ims.SrvccCall;
 import android.telephony.ims.feature.CapabilityChangeRequest;
@@ -51,6 +54,8 @@
     private TestImsSmsImpl mSmsImpl;
     private Set<RtpHeaderExtensionType> mOfferedRtpHeaderExtensionTypes;
     private CountDownLatch mOfferedRtpHeaderExtensionLatch = new CountDownLatch(1);
+    private MediaThreshold mSetMediaThreshold;
+    private CountDownLatch mSetMediaThresholdLatch = new CountDownLatch(1);
     private TestImsCallSessionImpl mCallSession;
     private CountDownLatch mTerminalBasedCallWaitingLatch = new CountDownLatch(1);
     private boolean mIsTerminalBasedCallWaitingNotified = false;
@@ -139,6 +144,13 @@
     }
 
     @Override
+    public void setMediaThreshold(int sessionType, MediaThreshold threshold) {
+        Log.d(TAG, "setMediaThreshold" + threshold);
+        mSetMediaThreshold = threshold;
+        mSetMediaThresholdLatch.countDown();
+    }
+
+    @Override
     public ImsCallProfile createCallProfile(int serviceType, int callType) {
         ImsStreamMediaProfile mediaProfile = new ImsStreamMediaProfile(
                 ImsStreamMediaProfile.AUDIO_QUALITY_AMR,
@@ -190,6 +202,21 @@
         mSrvccStartedCallback = null;
     }
 
+    @Override
+    public MediaQualityStatus queryMediaQualityStatus(int sessionType) {
+        if (!mCallSession.isInCall()) {
+            Log.d(TAG, "queryMediaQualityStatus: no call.");
+            return null;
+        }
+        MediaQualityStatus status = new MediaQualityStatus.Builder(mCallSession.getCallId(),
+                    MediaQualityStatus.MEDIA_SESSION_TYPE_AUDIO,
+                    AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                .setRtpPacketLossRate(0).setRtpJitterMillis(0).setRtpInactivityMillis(0).build();
+
+        Log.d(TAG, "queryMediaQualityStatus: current status " + status);
+        return status;
+    }
+
     public void setCapabilities(MmTelCapabilities capabilities) {
         mCapabilities = capabilities;
     }
@@ -206,6 +233,15 @@
         return mOfferedRtpHeaderExtensionLatch;
     }
 
+    public MediaThreshold getSetMediaThreshold() {
+        Log.d(TAG, "getSetMediaThreshold: " + mSetMediaThreshold);
+        return mSetMediaThreshold;
+    }
+
+    public CountDownLatch getSetMediaThresholdLatch() {
+        return mSetMediaThresholdLatch;
+    }
+
     public TestImsCallSessionImpl getImsCallsession() {
         return mCallSession;
     }