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.ThirdPartyCallScreeningServiceTest.EXTRA_NETWORK_IDENTIFIED_EMERGENCY_CALL;
20 
21 import android.net.Uri;
22 import android.os.Bundle;
23 import android.telecom.Conference;
24 import android.telecom.Connection;
25 import android.telecom.ConnectionRequest;
26 import android.telecom.ConnectionService;
27 import android.telecom.DisconnectCause;
28 import android.telecom.PhoneAccountHandle;
29 import android.telecom.RemoteConference;
30 import android.telecom.RemoteConnection;
31 import android.telecom.TelecomManager;
32 import android.util.Log;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.concurrent.Semaphore;
37 import java.util.concurrent.TimeUnit;
38 
39 /**
40  * Default implementation of a {@link CtsConnectionService}. This is used for the majority
41  * of Telecom CTS tests that simply require that a outgoing call is placed, or incoming call is
42  * received.
43  */
44 public class MockConnectionService extends ConnectionService {
45     public static final Uri VERSTAT_NOT_VERIFIED_NUMBER = Uri.fromParts("tel", "777", null);
46     public static final Uri VERSTAT_PASSED_NUMBER = Uri.fromParts("tel", "555", null);
47     public static final Uri VERSTAT_FAILED_NUMBER = Uri.fromParts("tel", "333", null);
48     public static final String EXTRA_TEST = "com.android.telecom.extra.TEST";
49     public static final String TEST_VALUE = "we've got it";
50     public static final int CONNECTION_PRESENTATION =  TelecomManager.PRESENTATION_ALLOWED;
51 
52     public static final int EVENT_CONNECTION_SERVICE_FOCUS_GAINED = 0;
53     public static final int EVENT_CONNECTION_SERVICE_FOCUS_LOST = 1;
54     public static final int EVENT_CONNECTION_SERVICE_CREATE_CONNECTION = 2;
55     public static final int EVENT_CONNECTION_SERVICE_CREATE_CONNECTION_FAILED = 3;
56     // Update TOTAL_EVENT below with last event.
57     private static final int TOTAL_EVENT = EVENT_CONNECTION_SERVICE_CREATE_CONNECTION_FAILED + 1;
58 
59     private static final int DEFAULT_EVENT_TIMEOUT_MS = 2000;
60 
61     private final Semaphore[] mEventLock = initializeSemaphore(TOTAL_EVENT);
62 
63     /**
64      * Used to control whether the {@link MockVideoProvider} will be created when connections are
65      * created.  Used by {@link VideoCallTest#testVideoCallDelayProvider()} to test scenario where
66      * the {@link MockVideoProvider} is not created immediately when the Connection is created.
67      */
68     private boolean mCreateVideoProvider = true;
69 
70     public Semaphore lock = new Semaphore(0);
71     public List<MockConnection> outgoingConnections = new ArrayList<MockConnection>();
72     public List<MockConnection> incomingConnections = new ArrayList<MockConnection>();
73     public List<RemoteConnection> remoteConnections = new ArrayList<RemoteConnection>();
74     public List<MockConference> conferences = new ArrayList<MockConference>();
75     public List<RemoteConference> remoteConferences = new ArrayList<RemoteConference>();
76     public List<MockConnection> failedConnections = new ArrayList<>();
77     public ConnectionRequest connectionRequest = null;
78 
79     @Override
onCreateOutgoingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)80     public Connection onCreateOutgoingConnection(PhoneAccountHandle connectionManagerPhoneAccount,
81             ConnectionRequest request) {
82         final MockConnection connection = new MockConnection();
83         connection.setAddress(request.getAddress(), CONNECTION_PRESENTATION);
84         connection.setMockPhoneAccountHandle(connectionManagerPhoneAccount);
85         connection.setConnectionCapabilities(Connection.CAPABILITY_SUPPORT_HOLD |
86                 Connection.CAPABILITY_HOLD
87                 | Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL
88                 | Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
89         if (mCreateVideoProvider) {
90             connection.createMockVideoProvider();
91         } else {
92             mCreateVideoProvider = true;
93         }
94         connection.setVideoState(request.getVideoState());
95         connection.setInitializing();
96         if (request.isRequestingRtt()) {
97             connection.setRttTextStream(request.getRttTextStream());
98             connection.setConnectionProperties(connection.getConnectionProperties() |
99                     Connection.PROPERTY_IS_RTT);
100         }
101         // Emit an extra into the connection.  We'll see if it makes it through.
102         Bundle testExtra = new Bundle();
103         testExtra.putString(EXTRA_TEST, TEST_VALUE);
104         connection.putExtras(testExtra);
105         outgoingConnections.add(connection);
106         lock.release();
107         mEventLock[EVENT_CONNECTION_SERVICE_CREATE_CONNECTION].release();
108         return connection;
109     }
110 
111     @Override
onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)112     public Connection onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount,
113             ConnectionRequest request) {
114         final MockConnection connection = new MockConnection();
115         connection.setAddress(request.getAddress(), CONNECTION_PRESENTATION);
116         connection.setConnectionCapabilities(connection.getConnectionCapabilities()
117                 | Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION
118                 | Connection.CAPABILITY_SUPPORT_HOLD
119                 | Connection.CAPABILITY_HOLD);
120         connection.createMockVideoProvider();
121         ((Connection) connection).setVideoState(request.getVideoState());
122         if (request.isRequestingRtt()) {
123             connection.setRttTextStream(request.getRttTextStream());
124             connection.setConnectionProperties(connection.getConnectionProperties() |
125                     Connection.PROPERTY_IS_RTT);
126         }
127         connection.setRinging();
128         // Emit an extra into the connection.  We'll see if it makes it through.
129         Bundle testExtra = new Bundle();
130         testExtra.putString(EXTRA_TEST, TEST_VALUE);
131         connection.putExtras(testExtra);
132         if (VERSTAT_NOT_VERIFIED_NUMBER.equals(request.getAddress())) {
133             connection.setCallerNumberVerificationStatus(
134                     Connection.VERIFICATION_STATUS_NOT_VERIFIED);
135         } else if (VERSTAT_PASSED_NUMBER.equals(request.getAddress())) {
136             connection.setCallerNumberVerificationStatus(
137                     Connection.VERIFICATION_STATUS_PASSED);
138         } else if (VERSTAT_FAILED_NUMBER.equals(request.getAddress())) {
139             connection.setCallerNumberVerificationStatus(
140                     Connection.VERIFICATION_STATUS_FAILED);
141         }
142 
143         Bundle requestExtra = request.getExtras();
144         if (requestExtra.getBoolean(EXTRA_NETWORK_IDENTIFIED_EMERGENCY_CALL, false)) {
145             connection.setConnectionProperties(
146                     Connection.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL);
147         }
148         incomingConnections.add(connection);
149         lock.release();
150         mEventLock[EVENT_CONNECTION_SERVICE_CREATE_CONNECTION].release();
151         return connection;
152     }
153 
154     @Override
onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)155     public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
156             ConnectionRequest request) {
157         final MockConnection connection = new MockConnection();
158         connection.setAddress(request.getAddress(), CONNECTION_PRESENTATION);
159         connection.setPhoneAccountHandle(connectionManagerPhoneAccount);
160         failedConnections.add(connection);
161         lock.release();
162         mEventLock[EVENT_CONNECTION_SERVICE_CREATE_CONNECTION_FAILED].release();
163     }
164 
165     @Override
onConference(Connection connection1, Connection connection2)166     public void onConference(Connection connection1, Connection connection2) {
167         // Make sure that these connections are already not conferenced.
168         if (connection1.getConference() == null && connection2.getConference() == null) {
169             MockConference conference = new MockConference(
170                     (MockConnection)connection1, (MockConnection)connection2);
171             CtsConnectionService.addConferenceToTelecom(conference);
172             conferences.add(conference);
173 
174             if (connection1.getState() == Connection.STATE_HOLDING){
175                 connection1.setActive();
176             }
177             if(connection2.getState() == Connection.STATE_HOLDING){
178                 connection2.setActive();
179             }
180 
181             lock.release();
182         }
183     }
184     @Override
onCreateOutgoingConference(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)185     public Conference onCreateOutgoingConference(PhoneAccountHandle connectionManagerPhoneAccount,
186             ConnectionRequest request) {
187         final Connection connection = onCreateOutgoingConnection(connectionManagerPhoneAccount,
188                 request);
189         final MockConference conference = new MockConference(connectionManagerPhoneAccount);
190         conference.addConnection(connection);
191         conferences.add(conference);
192         connectionRequest = request;
193         lock.release();
194         return conference;
195     }
196 
197     @Override
onCreateOutgoingConferenceFailed(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)198     public void onCreateOutgoingConferenceFailed(PhoneAccountHandle connectionManagerPhoneAccount,
199             ConnectionRequest request) {
200         final MockConference conference = new MockConference(connectionManagerPhoneAccount);
201         conference.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED));
202         conferences.add(conference);
203         connectionRequest = request;
204         lock.release(2);
205     }
206 
207     @Override
onCreateIncomingConference(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)208     public Conference onCreateIncomingConference(PhoneAccountHandle connectionManagerPhoneAccount,
209             ConnectionRequest request) {
210         final Connection connection = onCreateIncomingConnection(connectionManagerPhoneAccount,
211                 request);
212         final MockConference conference = new MockConference(connectionManagerPhoneAccount);
213         conference.addConnection(connection);
214         connectionRequest = request;
215         conferences.add(conference);
216         lock.release();
217         return conference;
218     }
219 
220     @Override
onCreateIncomingConferenceFailed(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)221     public void onCreateIncomingConferenceFailed(PhoneAccountHandle connectionManagerPhoneAccount,
222             ConnectionRequest request) {
223         final MockConference conference = new MockConference(connectionManagerPhoneAccount);
224         conference.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED));
225         conferences.add(conference);
226         connectionRequest = request;
227         lock.release(2);
228     }
229 
230     @Override
onRemoteExistingConnectionAdded(RemoteConnection connection)231     public void onRemoteExistingConnectionAdded(RemoteConnection connection) {
232         // Keep track of the remote connections added to the service
233         remoteConnections.add(connection);
234     }
235 
236     @Override
onRemoteConferenceAdded(RemoteConference conference)237     public void onRemoteConferenceAdded(RemoteConference conference) {
238         // Keep track of the remote connections added to the service
239         remoteConferences.add(conference);
240     }
241 
242     @Override
onConnectionServiceFocusGained()243     public void onConnectionServiceFocusGained() {
244         mEventLock[EVENT_CONNECTION_SERVICE_FOCUS_GAINED].release();
245     }
246 
247     @Override
onConnectionServiceFocusLost()248     public void onConnectionServiceFocusLost() {
249         mEventLock[EVENT_CONNECTION_SERVICE_FOCUS_LOST].release();
250         connectionServiceFocusReleased();
251     }
252 
setCreateVideoProvider(boolean createVideoProvider)253     public void setCreateVideoProvider(boolean createVideoProvider) {
254         mCreateVideoProvider = createVideoProvider;
255     }
256 
257     /** Returns true if the given {@code event} is happened before the default timeout. */
waitForEvent(int event)258     public boolean waitForEvent(int event) {
259         if (event < 0 || event >= mEventLock.length) {
260             return false;
261         }
262 
263         try {
264             return mEventLock[event].tryAcquire(DEFAULT_EVENT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
265         } catch (InterruptedException e) {
266             // No interaction for the given event within the given timeout.
267             return false;
268         }
269     }
270 
initializeSemaphore(int total)271     private static final Semaphore[] initializeSemaphore(int total) {
272         Semaphore[] locks = new Semaphore[total];
273         for (int i = 0; i < total; i++) {
274             locks[i] = new Semaphore(0);
275         }
276         return locks;
277     }
278 }
279