1 /*
2  * Copyright (C) 2015 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;
18 
19 import static android.telecom.cts.TestUtils.*;
20 
21 import static org.hamcrest.CoreMatchers.not;
22 import static org.hamcrest.CoreMatchers.equalTo;
23 import static org.junit.Assert.assertThat;
24 
25 import android.content.ComponentName;
26 import android.telecom.Connection;
27 import android.telecom.PhoneAccount;
28 import android.telecom.PhoneAccountHandle;
29 import android.telecom.RemoteConference;
30 import android.telecom.RemoteConnection;
31 import android.text.TextUtils;
32 import android.util.Log;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.concurrent.TimeUnit;
37 
38 /**
39  * Base class for Telecom CTS tests that require a {@link CtsConnectionService} and
40  * {@link CtsRemoteConnectionService} to verify Telecom functionality. This class
41  * extends from the {@link BaseTelecomTestWithMockServices} and should be extended
42  * for all RemoteConnection/RemoteConferencTest.
43  */
44 public class BaseRemoteTelecomTest extends BaseTelecomTestWithMockServices {
45 
46     public static final PhoneAccountHandle TEST_REMOTE_PHONE_ACCOUNT_HANDLE =
47             new PhoneAccountHandle(new ComponentName(PACKAGE, REMOTE_COMPONENT), REMOTE_ACCOUNT_ID);
48     public static final String TEST_REMOTE_PHONE_ACCOUNT_ADDRESS = "tel:666-TEST";
49 
50     MockConnectionService remoteConnectionService = null;
51 
52     @Override
tearDown()53     protected void tearDown() throws Exception {
54         if (mShouldTestTelecom) {
55             tearDownRemoteConnectionService(TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
56         }
57         super.tearDown();
58     }
59 
setupConnectionServices(MockConnectionService connectionService, MockConnectionService remoteConnectionService, int flags)60     protected void setupConnectionServices(MockConnectionService connectionService,
61             MockConnectionService remoteConnectionService, int flags) throws Exception {
62         // Setup the primary connection service first
63         setupConnectionService(connectionService, flags);
64         setupRemoteConnectionService(remoteConnectionService, flags);
65     }
66 
setupRemoteConnectionService(MockConnectionService remoteConnectionService, int flags)67     protected void setupRemoteConnectionService(MockConnectionService remoteConnectionService,
68             int flags) throws Exception {
69         if (remoteConnectionService != null) {
70             this.remoteConnectionService = remoteConnectionService;
71         } else {
72             // Generate a vanilla mock connection service, if not provided.
73             this.remoteConnectionService = new MockConnectionService();
74         }
75         CtsRemoteConnectionService.setUp(TEST_REMOTE_PHONE_ACCOUNT_HANDLE,
76                 this.remoteConnectionService);
77 
78         if ((flags & FLAG_REGISTER) != 0) {
79             // This needs SIM subscription, so register via adb commands to get system permission.
80             TestUtils.registerSimPhoneAccount(getInstrumentation(),
81                     TEST_REMOTE_PHONE_ACCOUNT_HANDLE,
82                     REMOTE_ACCOUNT_LABEL,
83                     TEST_REMOTE_PHONE_ACCOUNT_ADDRESS);
84             // Wait till the adb commands have executed and account is in Telecom database.
85             assertPhoneAccountRegistered(TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
86         }
87         if ((flags & FLAG_ENABLE) != 0) {
88             TestUtils.enablePhoneAccount(getInstrumentation(), TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
89             // Wait till the adb commands have executed and account is enabled in Telecom database.
90             assertPhoneAccountEnabled(TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
91         }
92     }
93 
tearDownRemoteConnectionService(PhoneAccountHandle remoteAccountHandle)94     protected void tearDownRemoteConnectionService(PhoneAccountHandle remoteAccountHandle)
95             throws Exception {
96         assertNumConnections(this.remoteConnectionService, 0);
97         mTelecomManager.unregisterPhoneAccount(remoteAccountHandle);
98         CtsRemoteConnectionService.tearDown();
99         //Telecom doesn't unbind the remote connection service at the end of all calls today.
100         //assertCtsRemoteConnectionServiceUnbound();
101         this.remoteConnectionService = null;
102     }
103 
verifyConnectionForOutgoingCallOnRemoteCS()104     MockConnection verifyConnectionForOutgoingCallOnRemoteCS() {
105         // Assuming only 1 connection present
106         return verifyConnectionForOutgoingCallOnRemoteCS(0);
107     }
108 
verifyConnectionForOutgoingCallOnRemoteCS(int connectionIndex)109     MockConnection verifyConnectionForOutgoingCallOnRemoteCS(int connectionIndex) {
110         try {
111             if (!remoteConnectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
112                     TimeUnit.MILLISECONDS)) {
113                 fail("No outgoing call connection requested by Telecom");
114             }
115         } catch (InterruptedException e) {
116             Log.i(TAG, "Test interrupted!");
117         }
118 
119         assertThat("Telecom should create outgoing connection for remote outgoing call",
120                 remoteConnectionService.outgoingConnections.size(), not(equalTo(0)));
121         assertEquals("Telecom should not create incoming connections for remote outgoing calls",
122                 0, remoteConnectionService.incomingConnections.size());
123         MockConnection connection = remoteConnectionService.outgoingConnections.get(connectionIndex);
124         return connection;
125     }
126 
verifyConnectionForIncomingCallOnRemoteCS()127     MockConnection verifyConnectionForIncomingCallOnRemoteCS() {
128         // Assuming only 1 connection present
129         return verifyConnectionForIncomingCallOnRemoteCS(0);
130     }
131 
verifyConnectionForIncomingCallOnRemoteCS(int connectionIndex)132     MockConnection verifyConnectionForIncomingCallOnRemoteCS(int connectionIndex) {
133         try {
134             if (!remoteConnectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
135                     TimeUnit.MILLISECONDS)) {
136                 fail("No outgoing call connection requested by Telecom");
137             }
138         } catch (InterruptedException e) {
139             Log.i(TAG, "Test interrupted!");
140         }
141 
142         assertThat("Telecom should create incoming connections for remote incoming calls",
143                 remoteConnectionService.incomingConnections.size(), not(equalTo(0)));
144         assertEquals("Telecom should not create outgoing connections for remote incoming calls",
145                 0, remoteConnectionService.outgoingConnections.size());
146         MockConnection connection = remoteConnectionService.incomingConnections.get(connectionIndex);
147         setAndVerifyConnectionForIncomingCall(connection);
148         return connection;
149     }
150 
setAndVerifyConferenceablesForOutgoingConnectionOnRemoteCS(int connectionIndex)151     void setAndVerifyConferenceablesForOutgoingConnectionOnRemoteCS(int connectionIndex) {
152         assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits());
153         /**
154          * Set the conferenceable connections on the given connection and it's remote connection
155          * counterpart.
156          */
157         // Make all other outgoing connections as conferenceable with this remote connection.
158         MockConnection connection = remoteConnectionService.outgoingConnections.get(connectionIndex);
159         List<Connection> confConnections =
160                 new ArrayList<>(remoteConnectionService.outgoingConnections.size());
161         for (Connection c : remoteConnectionService.outgoingConnections) {
162             if (c != connection) {
163                 confConnections.add(c);
164             }
165         }
166         connection.setConferenceableConnections(confConnections);
167         assertEquals(connection.getConferenceables(), confConnections);
168     }
169 
verifyConferenceForOutgoingCallOnRemoteCS()170     MockConference verifyConferenceForOutgoingCallOnRemoteCS() {
171         try {
172             if (!remoteConnectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
173                     TimeUnit.MILLISECONDS)) {
174                 fail("No outgoing conference requested by Telecom");
175             }
176         } catch (InterruptedException e) {
177             Log.i(TAG, "Test interrupted!");
178         }
179         // Return the newly created conference object to the caller
180         MockConference conference = remoteConnectionService.conferences.get(0);
181         setAndVerifyConferenceForOutgoingCall(conference);
182         return conference;
183     }
184 
assertRemoteConnectionState(final RemoteConnection connection, final int state)185     void assertRemoteConnectionState(final RemoteConnection connection, final int state) {
186         waitUntilConditionIsTrueOrTimeout(
187                 new Condition() {
188                     @Override
189                     public Object expected() {
190                         return state;
191                     }
192 
193                     @Override
194                     public Object actual() {
195                         return connection.getState();
196                     }
197                 },
198                 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
199                 "Remote Connection should be in state " + state
200         );
201     }
202 
assertRemoteConferenceState(final RemoteConference conference, final int state)203     void assertRemoteConferenceState(final RemoteConference conference, final int state) {
204         waitUntilConditionIsTrueOrTimeout(
205                 new Condition() {
206                     @Override
207                     public Object expected() {
208                         return state;
209                     }
210 
211                     @Override
212                     public Object actual() {
213                         return conference.getState();
214                     }
215                 },
216                 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
217                 "Remote Conference should be in state " + state
218         );
219     }
220 
assertCtsRemoteConnectionServiceUnbound()221     void assertCtsRemoteConnectionServiceUnbound() {
222         waitUntilConditionIsTrueOrTimeout(
223                 new Condition() {
224                     @Override
225                     public Object expected(){
226                         return true;
227                     }
228 
229                     @Override
230                     public Object actual() {
231                         return CtsRemoteConnectionService.isServiceUnbound();
232                     }
233                 },
234                 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
235                 "CtsRemoteConnectionService not yet unbound!"
236         );
237     }
238 }
239