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