• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 android.telecom.cts.cuj.app.integration;
18 
19 import static android.telecom.Call.STATE_ACTIVE;
20 import static android.telecom.Call.STATE_DIALING;
21 import static android.telecom.Call.STATE_DISCONNECTED;
22 import static android.telecom.Call.STATE_HOLDING;
23 import static android.telecom.Call.STATE_RINGING;
24 import static android.telecom.cts.apps.TelecomTestApp.ConnectionServiceVoipAppMain;
25 import static android.telecom.cts.apps.TelecomTestApp.ManagedConnectionServiceApp;
26 import static android.telecom.cts.apps.TelecomTestApp.ManagedConnectionServiceAppClone;
27 import static android.telecom.cts.apps.TelecomTestApp.TransactionalVoipAppMain;
28 
29 import static org.junit.Assert.assertEquals;
30 import static org.junit.Assert.assertNotNull;
31 import static org.junit.Assume.assumeTrue;
32 
33 import android.platform.test.annotations.RequiresFlagsEnabled;
34 import android.telecom.cts.apps.AppControlWrapper;
35 import android.telecom.cts.apps.CallSequencingValidator;
36 import android.telecom.cts.apps.CallStateTransitionOperation;
37 import android.telecom.cts.apps.TelecomTestApp;
38 import android.telecom.cts.cuj.BaseAppVerifier;
39 import android.telecom.cts.cuj.TestUtils;
40 
41 import com.android.server.telecom.flags.Flags;
42 
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 import org.junit.runners.Parameterized;
46 
47 import java.util.ArrayList;
48 import java.util.List;
49 
50 /** Call sequencing multi-call tests dealing with ECC */
51 @RunWith(Parameterized.class)
52 @RequiresFlagsEnabled({Flags.FLAG_ENABLE_CALL_SEQUENCING})
53 public class CallSequencingMultiCallEmergencyCallTest extends BaseAppVerifier {
54     /**
55      * Test parameters that consist of the following information: (1) telecom test apps being used
56      * for the normal + normal + ECC (2) the call holdable state of the 1st + 2nd calls and if the
57      * 2nd call is an outgoing call. (3) the expected call states of the 1st + 2nd calls after
58      * placing the 2nd call and the call states of the same calls after the ECC is placed. The last
59      * value indicates how many calls should be disconnected as a result of placing the ECC.
60      */
61     private static TelecomTestApp[][] sTelecomTestApps = {
62         /* 1st call test app
63          * 2nd call test app
64          * ECC test app (expectation)
65          */
66         {
67             ManagedConnectionServiceAppClone,
68             ManagedConnectionServiceApp,
69             ManagedConnectionServiceApp
70         }, // 1
71         {
72             ManagedConnectionServiceApp,
73             ManagedConnectionServiceAppClone,
74             ManagedConnectionServiceAppClone
75         }, // 2
76         {
77             ManagedConnectionServiceApp, ManagedConnectionServiceApp, ManagedConnectionServiceApp
78         }, // 3
79         {TransactionalVoipAppMain, ManagedConnectionServiceApp, ManagedConnectionServiceApp}, // 4
80         {ManagedConnectionServiceApp, TransactionalVoipAppMain, ManagedConnectionServiceApp}, // 5
81         {
82             ConnectionServiceVoipAppMain, ManagedConnectionServiceApp, ManagedConnectionServiceApp
83         }, // 6
84         {
85             ManagedConnectionServiceApp, ConnectionServiceVoipAppMain, ManagedConnectionServiceApp
86         }, // 7
87         {
88             ManagedConnectionServiceApp,
89             ManagedConnectionServiceAppClone,
90             ManagedConnectionServiceApp
91         }, // 8
92         {
93             ManagedConnectionServiceAppClone,
94             ManagedConnectionServiceApp,
95             ManagedConnectionServiceAppClone
96         }, // 9
97         {
98             ManagedConnectionServiceApp, ManagedConnectionServiceApp, ManagedConnectionServiceApp
99         }, // 10
100         {
101             ManagedConnectionServiceApp,
102             ManagedConnectionServiceAppClone,
103             ManagedConnectionServiceApp
104         }, // 11
105         {
106             ManagedConnectionServiceAppClone,
107             ManagedConnectionServiceApp,
108             ManagedConnectionServiceAppClone
109         }, // 12
110         // Todo: - Disabling this test for now (this will be corrected by b/403620519)
111         //        {
112         //            ManagedConnectionServiceApp, ManagedConnectionServiceApp,
113         // ManagedConnectionServiceApp
114         //        }, // 13
115         {
116             ManagedConnectionServiceApp,
117             ManagedConnectionServiceAppClone,
118             ManagedConnectionServiceApp
119         }, // 14
120         {
121             ManagedConnectionServiceAppClone,
122             ManagedConnectionServiceApp,
123             ManagedConnectionServiceAppClone
124         }, // 15
125         {TransactionalVoipAppMain, ManagedConnectionServiceApp, ManagedConnectionServiceApp}, // 16
126         {
127             ConnectionServiceVoipAppMain, ManagedConnectionServiceApp, ManagedConnectionServiceApp
128         }, // 17
129         {
130             ManagedConnectionServiceApp,
131             ManagedConnectionServiceAppClone,
132             ManagedConnectionServiceApp
133         }, // 18
134         {
135             ManagedConnectionServiceAppClone,
136             ManagedConnectionServiceApp,
137             ManagedConnectionServiceAppClone
138         }, // 19
139         {
140             ManagedConnectionServiceApp, ManagedConnectionServiceApp, ManagedConnectionServiceApp
141         }, // 20
142         {
143             ManagedConnectionServiceApp, ManagedConnectionServiceApp, ManagedConnectionServiceApp
144         }, // 21
145     };
146 
147     private static boolean[][] sCallsHoldableAndSecondCallOutgoing = {
148         /* is1stCallHoldable,
149          * is2ndCallHoldable,
150          * is2ndCallOutgoing
151          */
152         /* holdable tests */
153         {true, true, true}, // 1
154         {true, true, true}, // 2
155         {true, true, true}, // 3
156         {true, true, true}, // 4
157         {true, true, true}, // 5
158         {true, true, true}, // 6
159         {true, true, true}, // 7
160         {true, true, true}, // 8
161         {true, true, true}, // 9
162         {true, true, true}, // 10
163         {true, true, false}, // 11
164         {true, true, false}, // 12
165         //        {true, true, false}, // 13
166         /* non-holdable tests */
167         {true, false, true}, // 14
168         {true, false, true}, // 15
169         {true, false, true}, // 16
170         {true, false, true}, // 17
171         {false, true, false}, // 18
172         {false, true, false}, // 19
173         {false, false, false}, // 20
174         {false, false, true}, // 21
175     };
176     private static int[][] sExpectedCallStatesAndNumCallsDisconnected = {
177         /* expected1stCallStateAfter2nd,
178          * expected2ndCallStateAfter1st,
179          * expected1stCallStateAfterEcc,
180          * expected2ndCallStateAfterEcc,
181          * numDisconnectDueToEcc
182          */
183         {STATE_HOLDING, STATE_ACTIVE, STATE_DISCONNECTED, STATE_HOLDING, 1}, // 1
184         {STATE_HOLDING, STATE_ACTIVE, STATE_DISCONNECTED, STATE_HOLDING, 1}, // 2
185         {STATE_HOLDING, STATE_ACTIVE, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 3
186         {STATE_HOLDING, STATE_ACTIVE, STATE_DISCONNECTED, STATE_HOLDING, 1}, // 4
187         {STATE_HOLDING, STATE_ACTIVE, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 5
188         {STATE_HOLDING, STATE_ACTIVE, STATE_DISCONNECTED, STATE_HOLDING, 1}, // 6
189         {STATE_HOLDING, STATE_ACTIVE, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 7
190         {STATE_ACTIVE, STATE_DIALING, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 8
191         {STATE_ACTIVE, STATE_DIALING, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 9
192         {STATE_ACTIVE, STATE_DIALING, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 10
193         {STATE_ACTIVE, STATE_RINGING, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 11
194         {STATE_ACTIVE, STATE_RINGING, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 12
195         //        {STATE_ACTIVE, STATE_RINGING, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 13
196         {STATE_HOLDING, STATE_ACTIVE, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 14
197         {STATE_HOLDING, STATE_ACTIVE, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 15
198         {STATE_HOLDING, STATE_ACTIVE, STATE_DISCONNECTED, STATE_HOLDING, 1}, // 16
199         {STATE_HOLDING, STATE_ACTIVE, STATE_DISCONNECTED, STATE_HOLDING, 1}, // 17
200         {STATE_ACTIVE, STATE_RINGING, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 18
201         {STATE_ACTIVE, STATE_RINGING, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 19
202         {STATE_ACTIVE, STATE_RINGING, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 20
203         {STATE_HOLDING, STATE_ACTIVE, STATE_HOLDING, STATE_DISCONNECTED, 1}, // 21
204     };
205 
206     private static class CallParameters {
207         private TelecomTestApp[] mTestApps;
208         private int[] mExpectedCallStatesAndNumCallsDisconnected;
209         private boolean[] mCallsHoldableAndSecondCallOutgoing;
210 
CallParameters( TelecomTestApp[] testApps, int[] expectedCallStatesAndNumCallsDisconnected, boolean[] callsHoldableAndSecondCallOutgoing)211         CallParameters(
212                 TelecomTestApp[] testApps,
213                 int[] expectedCallStatesAndNumCallsDisconnected,
214                 boolean[] callsHoldableAndSecondCallOutgoing) {
215             mTestApps = testApps;
216             mExpectedCallStatesAndNumCallsDisconnected = expectedCallStatesAndNumCallsDisconnected;
217             mCallsHoldableAndSecondCallOutgoing = callsHoldableAndSecondCallOutgoing;
218         }
219 
getTestApps()220         private TelecomTestApp[] getTestApps() {
221             return mTestApps;
222         }
223 
getExpectedCallStatesAndNumsCallsDisconnected()224         private int[] getExpectedCallStatesAndNumsCallsDisconnected() {
225             return mExpectedCallStatesAndNumCallsDisconnected;
226         }
227 
getCallsHoldableAndSecondCallOutgoing()228         private boolean[] getCallsHoldableAndSecondCallOutgoing() {
229             return mCallsHoldableAndSecondCallOutgoing;
230         }
231 
232         @Override
toString()233         public String toString() {
234             StringBuilder nameBuilder = new StringBuilder();
235             nameBuilder.append("\nTelecom test apps for 1st + 2nd + 3rd call: ");
236             for (TelecomTestApp testApp : mTestApps) {
237                 nameBuilder.append(testApp);
238                 nameBuilder.append(", ");
239             }
240             nameBuilder.append(
241                     "\nFirst and second call holdability and second " + "call is outgoing: ");
242             for (boolean holdabilityOrOutgoingState : mCallsHoldableAndSecondCallOutgoing) {
243                 nameBuilder.append(holdabilityOrOutgoingState);
244                 nameBuilder.append(", ");
245             }
246             nameBuilder.append(
247                     "\n"
248                         + "Expected call states of 1st + 2nd call after placing 2nd call, 1st + 2nd"
249                         + " call after placing the ECC, and expected number of calls disconnected"
250                         + " as a result of placing the ECC: ");
251             for (int expectedCallStateOrNumsCallsDisconnected :
252                     mExpectedCallStatesAndNumCallsDisconnected) {
253                 nameBuilder.append(expectedCallStateOrNumsCallsDisconnected);
254                 nameBuilder.append(", ");
255             }
256             return nameBuilder.toString();
257         }
258     }
259 
260     @Override
setUp()261     public void setUp() throws Exception {
262         super.setUp();
263         // Emergency calling is not supported on devices without FEATURE_TELEPHONY
264         // or FEATURE_TELECOM (i.e. Tangor).
265         assumeTrue(mShouldTestTelecom && TestUtils.hasTelephonyFeature(mContext));
266         setupForEmergencyCalling();
267     }
268 
269     @Override
tearDown()270     public void tearDown() throws Exception {
271         super.tearDown();
272         tearDownEmergencyCalling();
273     }
274 
275     @Parameterized.Parameters(name = "{0}")
data()276     public static Iterable<CallParameters> data() {
277         List<CallParameters> params = new ArrayList<>();
278         for (int i = 0; i < sTelecomTestApps.length; i++) {
279             CallParameters param =
280                     new CallParameters(
281                             sTelecomTestApps[i],
282                             sExpectedCallStatesAndNumCallsDisconnected[i],
283                             sCallsHoldableAndSecondCallOutgoing[i]);
284             params.add(param);
285         }
286         return params;
287     }
288 
289     public final CallParameters mParams;
290 
CallSequencingMultiCallEmergencyCallTest(CallParameters params)291     public CallSequencingMultiCallEmergencyCallTest(CallParameters params) {
292         mParams = params;
293     }
294 
295     @Test
testMultiCallEcc()296     public void testMultiCallEcc() throws Exception {
297         TelecomTestApp[] testApps = mParams.getTestApps();
298         int[] expectedCallStatesAndNumCallsDisconnected =
299                 mParams.getExpectedCallStatesAndNumsCallsDisconnected();
300         boolean[] callsHoldableAndSecondCallOutgoing =
301                 mParams.getCallsHoldableAndSecondCallOutgoing();
302         assertEquals(testApps.length, 3);
303         assertEquals(callsHoldableAndSecondCallOutgoing.length, 3);
304         assertEquals(expectedCallStatesAndNumCallsDisconnected.length, 5);
305         verifyAddEccWithTwoCalls(
306                 testApps[0],
307                 testApps[1],
308                 testApps[2],
309                 callsHoldableAndSecondCallOutgoing[0],
310                 callsHoldableAndSecondCallOutgoing[1],
311                 callsHoldableAndSecondCallOutgoing[2],
312                 expectedCallStatesAndNumCallsDisconnected[0],
313                 expectedCallStatesAndNumCallsDisconnected[1],
314                 expectedCallStatesAndNumCallsDisconnected[2],
315                 expectedCallStatesAndNumCallsDisconnected[3],
316                 expectedCallStatesAndNumCallsDisconnected[4]);
317     }
318 
verifyAddEccWithTwoCalls( TelecomTestApp app1, TelecomTestApp app2, TelecomTestApp app3, boolean is1stCallHoldable, boolean is2ndCallHoldable, boolean is2ndCallOutgoing, int expected1stCallStateAfter2nd, int expected2ndCallStateAfter1st, int expected1stCallStateAfterEcc, int expected2ndCallStateAfterEcc, int numDisconnectDueToEcc)319     private void verifyAddEccWithTwoCalls(
320             TelecomTestApp app1,
321             TelecomTestApp app2,
322             TelecomTestApp app3,
323             boolean is1stCallHoldable,
324             boolean is2ndCallHoldable,
325             boolean is2ndCallOutgoing,
326             int expected1stCallStateAfter2nd,
327             int expected2ndCallStateAfter1st,
328             int expected1stCallStateAfterEcc,
329             int expected2ndCallStateAfterEcc,
330             int numDisconnectDueToEcc)
331             throws Exception {
332         AppControlWrapper controlWrapperApp1 = null;
333         AppControlWrapper controlWrapperApp2 = null;
334         AppControlWrapper controlWrapperApp3 = null;
335         CallSequencingValidator c1Validator = new CallSequencingValidator();
336         CallSequencingValidator c2Validator = new CallSequencingValidator();
337         CallSequencingValidator c3Validator = new CallSequencingValidator();
338 
339         try {
340             controlWrapperApp1 = bindToApp(app1);
341             controlWrapperApp2 = bindToApp(app2);
342             controlWrapperApp3 = bindToApp(app3);
343             // Place an outgoing managed call.
344             String call1 =
345                     addCallAndVerify(
346                             controlWrapperApp1,
347                             getRandomAttributes(app1, true /* isOutgoing */, is1stCallHoldable),
348                             c1Validator);
349             verifyCallIsInState(call1, STATE_DIALING);
350             verifyCallStateTransition(c1Validator, call1, controlWrapperApp1, STATE_ACTIVE);
351 
352             // Place another managed call and verify the existing call is either held or active (in
353             // the case of a dialing/ringing call).
354             String call2 =
355                     addCallAndVerify(
356                             controlWrapperApp2,
357                             getRandomAttributes(app2, is2ndCallOutgoing, is2ndCallHoldable),
358                             c2Validator);
359             if (expected1stCallStateAfter2nd != STATE_ACTIVE) {
360                 verifyCallStateTransition(
361                         c1Validator, call1, controlWrapperApp1, expected1stCallStateAfter2nd);
362             }
363             verifyCallStateTransition(
364                     c2Validator, call2, controlWrapperApp2, expected2ndCallStateAfter1st);
365 
366             // Place emergency call and verify the 1st and 2nd calls are either held/disconnected
367             // depending on the condition (Refer to the expected behavior from the test parameters
368             // above). The emergency call should go through the ManagedConnectionServiceApp phone
369             // account.
370             String emergencyCall =
371                     addEmergencyCallAndVerify(
372                             controlWrapperApp3, c3Validator, numDisconnectDueToEcc);
373             if (expected1stCallStateAfterEcc != expected1stCallStateAfter2nd) {
374                 verifyCallStateTransition(
375                         c1Validator, call1, controlWrapperApp1, expected1stCallStateAfterEcc);
376             }
377             if (expected2ndCallStateAfterEcc != expected2ndCallStateAfter1st) {
378                 verifyCallStateTransition(
379                         c2Validator, call2, controlWrapperApp2, expected2ndCallStateAfterEcc);
380             }
381             verifyCallIsInState(emergencyCall, STATE_DIALING);
382             setCallStateAndVerify(controlWrapperApp3, emergencyCall, STATE_ACTIVE);
383 
384             // Clean up calls
385             if (expected1stCallStateAfterEcc != STATE_DISCONNECTED) {
386                 setCallStateAndVerify(controlWrapperApp1, call1, STATE_DISCONNECTED);
387             }
388             if (expected2ndCallStateAfterEcc != STATE_DISCONNECTED) {
389                 setCallStateAndVerify(controlWrapperApp2, call2, STATE_DISCONNECTED);
390             }
391             setCallStateAndVerify(controlWrapperApp3, emergencyCall, STATE_DISCONNECTED);
392         } finally {
393             List<AppControlWrapper> controls = new ArrayList<>();
394             controls.add(controlWrapperApp1);
395             controls.add(controlWrapperApp2);
396             controls.add(controlWrapperApp3);
397             tearDownApps(controls);
398         }
399     }
400 
verifyCallStateTransition( CallSequencingValidator validator, String call, AppControlWrapper app, int expectedCallState)401     private void verifyCallStateTransition(
402             CallSequencingValidator validator,
403             String call,
404             AppControlWrapper app,
405             int expectedCallState)
406             throws Exception {
407         if (expectedCallState == STATE_ACTIVE) {
408             verifyCallIsInState(call, STATE_DIALING);
409             setCallStateAndVerify(app, call, STATE_ACTIVE);
410             return;
411         } else if (expectedCallState == STATE_RINGING || expectedCallState == STATE_DIALING) {
412             verifyCallIsInState(call, expectedCallState);
413             return;
414         }
415         int transitionOp = -1;
416         String opString = "";
417         if (expectedCallState == STATE_DISCONNECTED) {
418             transitionOp = CallStateTransitionOperation.OPERATION_DISCONNECT;
419             opString = "DISCONNECT";
420         } else if (expectedCallState == STATE_HOLDING) {
421             transitionOp = CallStateTransitionOperation.OPERATION_HOLD;
422             opString = "HOLD";
423         }
424         CallStateTransitionOperation op = validator.completePendingOperationOrTimeout(transitionOp);
425         assertNotNull(opString + " operation never received for call " + call, op);
426         verifyCallIsInState(call, expectedCallState);
427     }
428 }
429