1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony.metrics;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.mockito.Mockito.when;
21 
22 import android.telephony.CallQuality;
23 import android.telephony.CellSignalStrengthCdma;
24 import android.telephony.CellSignalStrengthGsm;
25 import android.telephony.CellSignalStrengthLte;
26 import android.telephony.CellSignalStrengthNr;
27 import android.telephony.CellSignalStrengthTdscdma;
28 import android.telephony.CellSignalStrengthWcdma;
29 import android.telephony.SignalStrength;
30 
31 import com.android.internal.telephony.TelephonyTest;
32 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.CallQualitySummary;
33 
34 import org.junit.After;
35 import org.junit.Before;
36 import org.junit.Test;
37 
38 public class CallQualityMetricsTest extends TelephonyTest {
39 
40     private CallQualityMetrics mCallQualityMetrics;
41 
42     @Before
setUp()43     public void setUp() throws Exception {
44         super.setUp(getClass().getSimpleName());
45         mCallQualityMetrics = new CallQualityMetrics(mPhone);
46 
47         // the ImsPhone does not return a ServiceStateTracker, so CallQualityMetrics gets the
48         // default phone from the ImsPhone and uses that to get the ServiceStateTracker, therefore
49         // we need to mock the default phone as well.
50         when(mPhone.getDefaultPhone()).thenReturn(mPhone);
51     }
52 
53     @After
tearDown()54     public void tearDown() throws Exception {
55         super.tearDown();
56     }
57 
constructCallQuality(int dlQuality, int ulQuality, int durationMs)58     private CallQuality constructCallQuality(int dlQuality, int ulQuality, int durationMs) {
59         return new CallQuality(
60                 dlQuality,
61                 ulQuality,
62                 durationMs,
63                 0, 0, 0, 0, 0, 0, 0, 0); // packets, jitter and codec (okay to ignore for testing)
64     }
65 
66     /**
67      * Verify that good/bad quality and total duration stats are correct.
68      */
69     @Test
testTotalDurations()70     public void testTotalDurations() {
71         // Call quality in the following sequence:
72         //
73         // DL: GOOD       GOOD      BAD
74         // UL: GOOD       BAD       GOOD
75         // |----------|----------|--------|
76         // 0          5          10       14
77         //
78         // 0s = Start of call. Assumed to be good quality
79         // 5s = Switches to UL bad quality
80         // 10s = Switches to UL good quality, DL bad quality
81         // 14s = End of call. Switches to UL bad quality, DL good quality
82         CallQuality cq1 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
83                 CallQuality.CALL_QUALITY_BAD, 5000);
84         CallQuality cq2 = constructCallQuality(CallQuality.CALL_QUALITY_BAD,
85                 CallQuality.CALL_QUALITY_EXCELLENT, 10000);
86         CallQuality cq3 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
87                 CallQuality.CALL_QUALITY_BAD, 14000);
88 
89         mCallQualityMetrics.saveCallQuality(cq1);
90         mCallQualityMetrics.saveCallQuality(cq2);
91         mCallQualityMetrics.saveCallQuality(cq3);
92 
93         // verify UL quality durations
94         CallQualitySummary dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
95         assertEquals(9, dlSummary.totalGoodQualityDurationInSeconds);
96         assertEquals(5, dlSummary.totalBadQualityDurationInSeconds);
97         assertEquals(14, dlSummary.totalDurationWithQualityInformationInSeconds);
98 
99         // verify DL quality durations
100         CallQualitySummary ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
101         assertEquals(5, ulSummary.totalGoodQualityDurationInSeconds);
102         assertEquals(9, ulSummary.totalBadQualityDurationInSeconds);
103         assertEquals(14, ulSummary.totalDurationWithQualityInformationInSeconds);
104     }
105 
106     /**
107      * Verify that good/bad quality and total duration stats are correct.
108      *
109      * Similar to testTotalDurations, but getCallQualitySummaryUl/Dl will be called multiple times,
110      * so verify that it continues to work after the first call.
111      */
112     @Test
testTotalDurations_MultipleChecks()113     public void testTotalDurations_MultipleChecks() {
114         // Call quality in the following sequence:
115         //
116         // DL: GOOD       GOOD      BAD
117         // UL: GOOD       BAD       GOOD
118         // |----------|----------|--------|
119         // 0          5          10       14
120         //
121         // 0s = Start of call. Assumed to be good quality
122         // 5s = Switches to UL bad quality
123         // 10s = Switches to UL good quality, DL bad quality
124         // 14s = End of call. Switches to UL bad quality, DL good quality
125         CallQuality cq1 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
126                 CallQuality.CALL_QUALITY_BAD, 5000);
127         CallQuality cq2 = constructCallQuality(CallQuality.CALL_QUALITY_BAD,
128                 CallQuality.CALL_QUALITY_EXCELLENT, 10000);
129         CallQuality cq3 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
130                 CallQuality.CALL_QUALITY_BAD, 14000);
131 
132         mCallQualityMetrics.saveCallQuality(cq1);
133         mCallQualityMetrics.saveCallQuality(cq2);
134         mCallQualityMetrics.saveCallQuality(cq3);
135 
136         // verify UL quality durations
137         CallQualitySummary dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
138         assertEquals(9, dlSummary.totalGoodQualityDurationInSeconds);
139         assertEquals(5, dlSummary.totalBadQualityDurationInSeconds);
140         assertEquals(14, dlSummary.totalDurationWithQualityInformationInSeconds);
141 
142         // verify DL quality durations
143         CallQualitySummary ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
144         assertEquals(5, ulSummary.totalGoodQualityDurationInSeconds);
145         assertEquals(9, ulSummary.totalBadQualityDurationInSeconds);
146         assertEquals(14, ulSummary.totalDurationWithQualityInformationInSeconds);
147 
148         // verify UL quality durations
149         dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
150         assertEquals(9, dlSummary.totalGoodQualityDurationInSeconds);
151         assertEquals(5, dlSummary.totalBadQualityDurationInSeconds);
152         assertEquals(14, dlSummary.totalDurationWithQualityInformationInSeconds);
153 
154         // verify DL quality durations
155         ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
156         assertEquals(5, ulSummary.totalGoodQualityDurationInSeconds);
157         assertEquals(9, ulSummary.totalBadQualityDurationInSeconds);
158         assertEquals(14, ulSummary.totalDurationWithQualityInformationInSeconds);
159     }
160 
161 
162     /**
163      * Verify that good/bad quality and total duration stats are correct.
164      *
165      * Similar to testTotalDurations but we report the call quality out of order.
166      */
167     @Test
testTotalDurations_ReportedOutOfOrder()168     public void testTotalDurations_ReportedOutOfOrder() {
169         // Call quality in the following sequence:
170         //
171         // DL: GOOD       GOOD      BAD
172         // UL: GOOD       BAD       GOOD
173         // |----------|----------|--------|
174         // 0          5          10       14
175         //
176         // 0s = Start of call. Assumed to be good quality
177         // 5s = Switches to UL bad quality
178         // 10s = Switches to UL good quality, DL bad quality
179         // 14s = End of call. Switches to UL bad quality, DL good quality
180         CallQuality cq1 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
181                 CallQuality.CALL_QUALITY_BAD, 5000);
182         CallQuality cq2 = constructCallQuality(CallQuality.CALL_QUALITY_BAD,
183                 CallQuality.CALL_QUALITY_EXCELLENT, 10000);
184         CallQuality cq3 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
185                 CallQuality.CALL_QUALITY_BAD, 14000);
186 
187         mCallQualityMetrics.saveCallQuality(cq1);
188         mCallQualityMetrics.saveCallQuality(cq3);
189         mCallQualityMetrics.saveCallQuality(cq2);
190 
191         // verify UL quality durations
192         CallQualitySummary dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
193         assertEquals(9, dlSummary.totalGoodQualityDurationInSeconds);
194         assertEquals(5, dlSummary.totalBadQualityDurationInSeconds);
195         assertEquals(14, dlSummary.totalDurationWithQualityInformationInSeconds);
196 
197         // verify DL quality durations
198         CallQualitySummary ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
199         assertEquals(5, ulSummary.totalGoodQualityDurationInSeconds);
200         assertEquals(9, ulSummary.totalBadQualityDurationInSeconds);
201         assertEquals(14, ulSummary.totalDurationWithQualityInformationInSeconds);
202     }
203 
204     /**
205      * Verify that a new CallQualityMetrics object is able to return empty summaries if no
206      * CallQuality is reported for the duration of a call.
207      */
208     @Test
testNoQualityReported()209     public void testNoQualityReported() {
210         // getting the summary for a new CallQualityMetrics object should not fail, and all
211         // durations should be 0
212         CallQualitySummary dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
213         assertEquals(0, dlSummary.totalGoodQualityDurationInSeconds);
214         assertEquals(0, dlSummary.totalBadQualityDurationInSeconds);
215         assertEquals(0, dlSummary.totalDurationWithQualityInformationInSeconds);
216         CallQualitySummary ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
217         assertEquals(0, ulSummary.totalGoodQualityDurationInSeconds);
218         assertEquals(0, ulSummary.totalBadQualityDurationInSeconds);
219         assertEquals(0, ulSummary.totalDurationWithQualityInformationInSeconds);
220     }
221 
222     /**
223      * Verify that if either UL or DL call quality level is not available, the CallQuality update is
224      * ignored.
225      */
226     @Test
testNotAvailableIsIgnored()227     public void testNotAvailableIsIgnored() {
228         // CallQuality updates from the IMS service with CALL_QUALITY_NOT_AVAILABLE should be
229         // ignored
230         CallQuality cq1 = constructCallQuality(CallQuality.CALL_QUALITY_NOT_AVAILABLE,
231                 CallQuality.CALL_QUALITY_BAD, 5000);
232         CallQuality cq2 = constructCallQuality(CallQuality.CALL_QUALITY_BAD,
233                 CallQuality.CALL_QUALITY_NOT_AVAILABLE, 10000);
234         mCallQualityMetrics.saveCallQuality(cq1);
235         mCallQualityMetrics.saveCallQuality(cq2);
236 
237         CallQualitySummary dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
238         assertEquals(0, dlSummary.totalGoodQualityDurationInSeconds);
239         assertEquals(0, dlSummary.totalBadQualityDurationInSeconds);
240         assertEquals(0, dlSummary.totalDurationWithQualityInformationInSeconds);
241         CallQualitySummary ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
242         assertEquals(0, ulSummary.totalGoodQualityDurationInSeconds);
243         assertEquals(0, ulSummary.totalBadQualityDurationInSeconds);
244         assertEquals(0, ulSummary.totalDurationWithQualityInformationInSeconds);
245     }
246 
247     /**
248      * Test that the best and worst SignalStrength (currently just LTE RSSNR) is correctly kept
249      * track of. CallQualityMetrics should log the best and worst SS for good and bad quality, but
250      * this just tests for good quality since the logic is the same.
251      */
252     @Test
testBestAndWorstSs()253     public void testBestAndWorstSs() {
254         // save good quality with high rssnr
255         CallQuality cq1 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
256                 CallQuality.CALL_QUALITY_EXCELLENT, 5000);
257         int rssnr1 = 30;
258         // ignore everything except rssnr
259         CellSignalStrengthLte lteSs1 = new CellSignalStrengthLte(0, 0, 0, rssnr1, 0, 0);
260         SignalStrength ss1 = new SignalStrength(
261                 new CellSignalStrengthCdma(),
262                 new CellSignalStrengthGsm(),
263                 new CellSignalStrengthWcdma(),
264                 new CellSignalStrengthTdscdma(),
265                 lteSs1,
266                 new CellSignalStrengthNr());
267         when(mSST.getSignalStrength()).thenReturn(ss1);
268         mCallQualityMetrics.saveCallQuality(cq1);
269 
270         // save good quality with low rssnr
271         CallQuality cq2 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
272                 CallQuality.CALL_QUALITY_EXCELLENT, 10000);
273         int rssnr2 = -20;
274         // ignore everything except rssnr
275         CellSignalStrengthLte lteSs2 = new CellSignalStrengthLte(0, 0, 0, rssnr2, 0, 0);
276         SignalStrength ss2 = new SignalStrength(
277                 new CellSignalStrengthCdma(),
278                 new CellSignalStrengthGsm(),
279                 new CellSignalStrengthWcdma(),
280                 new CellSignalStrengthTdscdma(),
281                 lteSs2,
282                 new CellSignalStrengthNr());
283         when(mSST.getSignalStrength()).thenReturn(ss2);
284         mCallQualityMetrics.saveCallQuality(cq1);
285 
286         CallQualitySummary dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
287         assertEquals(rssnr1, dlSummary.bestSsWithGoodQuality.lteSnr);
288         assertEquals(rssnr2, dlSummary.worstSsWithGoodQuality.lteSnr);
289     }
290 
291     /**
292      * Verifies that the snapshot of the end (the last reported call quality) is correct.
293      * Currently this just checks the duration since the logic is all the same and it doesn't seem
294      * likely that one field would be preserved and others would be lost.
295      */
296     @Test
testSnapshotOfEndDuration()297     public void testSnapshotOfEndDuration() {
298         CallQuality cq1 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
299                 CallQuality.CALL_QUALITY_BAD, 5000);
300         CallQuality cq2 = constructCallQuality(CallQuality.CALL_QUALITY_BAD,
301                 CallQuality.CALL_QUALITY_EXCELLENT, 10000);
302         CallQuality cq3 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
303                 CallQuality.CALL_QUALITY_BAD, 14000);
304 
305         mCallQualityMetrics.saveCallQuality(cq1);
306         mCallQualityMetrics.saveCallQuality(cq2);
307         mCallQualityMetrics.saveCallQuality(cq3);
308 
309         // verify snapshot of end
310         CallQualitySummary dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
311         assertEquals(14, dlSummary.snapshotOfEnd.durationInSeconds);
312         CallQualitySummary ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
313         assertEquals(14, ulSummary.snapshotOfEnd.durationInSeconds);
314     }
315 
316     /**
317      * Verifies that the snapshot of the end (the last reported call quality) is correct.
318      * Currently this just checks the duration since the logic is all the same and it doesn't seem
319      * likely that one field would be preserved and others would be lost.
320      *
321      * Similar to testSnapshotOfEndDuration but we report the call quality out of order
322      */
323     @Test
testSnapshotOfEndDuration_ReportedOutOfOrder()324     public void testSnapshotOfEndDuration_ReportedOutOfOrder() {
325         CallQuality cq1 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
326                 CallQuality.CALL_QUALITY_BAD, 5000);
327         CallQuality cq2 = constructCallQuality(CallQuality.CALL_QUALITY_BAD,
328                 CallQuality.CALL_QUALITY_EXCELLENT, 10000);
329         CallQuality cq3 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
330                 CallQuality.CALL_QUALITY_BAD, 14000);
331 
332         mCallQualityMetrics.saveCallQuality(cq1);
333         mCallQualityMetrics.saveCallQuality(cq3);
334         mCallQualityMetrics.saveCallQuality(cq2);
335 
336         // verify snapshot of end
337         CallQualitySummary dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
338         assertEquals(14, dlSummary.snapshotOfEnd.durationInSeconds);
339         CallQualitySummary ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
340         assertEquals(14, ulSummary.snapshotOfEnd.durationInSeconds);
341     }
342 }
343