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 Bundle testExtra; 102 if (request.getExtras() != null) { 103 testExtra = request.getExtras(); 104 } else { 105 testExtra = new Bundle(); 106 } 107 // Emit an extra into the connection. We'll see if it makes it through. 108 testExtra.putString(EXTRA_TEST, TEST_VALUE); 109 connection.putExtras(testExtra); 110 outgoingConnections.add(connection); 111 lock.release(); 112 mEventLock[EVENT_CONNECTION_SERVICE_CREATE_CONNECTION].release(); 113 return connection; 114 } 115 116 @Override onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)117 public Connection onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount, 118 ConnectionRequest request) { 119 final MockConnection connection = new MockConnection(); 120 connection.setAddress(request.getAddress(), CONNECTION_PRESENTATION); 121 connection.setConnectionCapabilities(connection.getConnectionCapabilities() 122 | Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION 123 | Connection.CAPABILITY_SUPPORT_HOLD 124 | Connection.CAPABILITY_HOLD); 125 connection.createMockVideoProvider(); 126 ((Connection) connection).setVideoState(request.getVideoState()); 127 if (request.isRequestingRtt()) { 128 connection.setRttTextStream(request.getRttTextStream()); 129 connection.setConnectionProperties(connection.getConnectionProperties() | 130 Connection.PROPERTY_IS_RTT); 131 } 132 connection.setRinging(); 133 // Emit an extra into the connection. We'll see if it makes it through. 134 Bundle testExtra = new Bundle(); 135 testExtra.putString(EXTRA_TEST, TEST_VALUE); 136 connection.putExtras(testExtra); 137 if (VERSTAT_NOT_VERIFIED_NUMBER.equals(request.getAddress())) { 138 connection.setCallerNumberVerificationStatus( 139 Connection.VERIFICATION_STATUS_NOT_VERIFIED); 140 } else if (VERSTAT_PASSED_NUMBER.equals(request.getAddress())) { 141 connection.setCallerNumberVerificationStatus( 142 Connection.VERIFICATION_STATUS_PASSED); 143 } else if (VERSTAT_FAILED_NUMBER.equals(request.getAddress())) { 144 connection.setCallerNumberVerificationStatus( 145 Connection.VERIFICATION_STATUS_FAILED); 146 } 147 148 Bundle requestExtra = request.getExtras(); 149 if (requestExtra.getBoolean(EXTRA_NETWORK_IDENTIFIED_EMERGENCY_CALL, false)) { 150 connection.setConnectionProperties( 151 Connection.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL); 152 } 153 incomingConnections.add(connection); 154 lock.release(); 155 mEventLock[EVENT_CONNECTION_SERVICE_CREATE_CONNECTION].release(); 156 return connection; 157 } 158 159 @Override onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)160 public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount, 161 ConnectionRequest request) { 162 final MockConnection connection = new MockConnection(); 163 connection.setAddress(request.getAddress(), CONNECTION_PRESENTATION); 164 connection.setPhoneAccountHandle(connectionManagerPhoneAccount); 165 failedConnections.add(connection); 166 lock.release(); 167 mEventLock[EVENT_CONNECTION_SERVICE_CREATE_CONNECTION_FAILED].release(); 168 } 169 170 @Override onConference(Connection connection1, Connection connection2)171 public void onConference(Connection connection1, Connection connection2) { 172 // Make sure that these connections are already not conferenced. 173 if (connection1.getConference() == null && connection2.getConference() == null) { 174 MockConference conference = new MockConference( 175 (MockConnection)connection1, (MockConnection)connection2); 176 CtsConnectionService.addConferenceToTelecom(conference); 177 conferences.add(conference); 178 179 if (connection1.getState() == Connection.STATE_HOLDING){ 180 connection1.setActive(); 181 } 182 if(connection2.getState() == Connection.STATE_HOLDING){ 183 connection2.setActive(); 184 } 185 186 lock.release(); 187 } 188 } 189 @Override onCreateOutgoingConference(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)190 public Conference onCreateOutgoingConference(PhoneAccountHandle connectionManagerPhoneAccount, 191 ConnectionRequest request) { 192 final Connection connection = onCreateOutgoingConnection(connectionManagerPhoneAccount, 193 request); 194 final MockConference conference = new MockConference(connectionManagerPhoneAccount); 195 conference.addConnection(connection); 196 conferences.add(conference); 197 connectionRequest = request; 198 lock.release(); 199 return conference; 200 } 201 202 @Override onCreateOutgoingConferenceFailed(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)203 public void onCreateOutgoingConferenceFailed(PhoneAccountHandle connectionManagerPhoneAccount, 204 ConnectionRequest request) { 205 final MockConference conference = new MockConference(connectionManagerPhoneAccount); 206 conference.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED)); 207 conferences.add(conference); 208 connectionRequest = request; 209 lock.release(2); 210 } 211 212 @Override onCreateIncomingConference(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)213 public Conference onCreateIncomingConference(PhoneAccountHandle connectionManagerPhoneAccount, 214 ConnectionRequest request) { 215 final Connection connection = onCreateIncomingConnection(connectionManagerPhoneAccount, 216 request); 217 final MockConference conference = new MockConference(connectionManagerPhoneAccount); 218 conference.addConnection(connection); 219 connectionRequest = request; 220 conferences.add(conference); 221 lock.release(); 222 return conference; 223 } 224 225 @Override onCreateIncomingConferenceFailed(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)226 public void onCreateIncomingConferenceFailed(PhoneAccountHandle connectionManagerPhoneAccount, 227 ConnectionRequest request) { 228 final MockConference conference = new MockConference(connectionManagerPhoneAccount); 229 conference.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED)); 230 conferences.add(conference); 231 connectionRequest = request; 232 lock.release(2); 233 } 234 235 @Override onRemoteExistingConnectionAdded(RemoteConnection connection)236 public void onRemoteExistingConnectionAdded(RemoteConnection connection) { 237 // Keep track of the remote connections added to the service 238 remoteConnections.add(connection); 239 } 240 241 @Override onRemoteConferenceAdded(RemoteConference conference)242 public void onRemoteConferenceAdded(RemoteConference conference) { 243 // Keep track of the remote connections added to the service 244 remoteConferences.add(conference); 245 } 246 247 @Override onConnectionServiceFocusGained()248 public void onConnectionServiceFocusGained() { 249 mEventLock[EVENT_CONNECTION_SERVICE_FOCUS_GAINED].release(); 250 } 251 252 @Override onConnectionServiceFocusLost()253 public void onConnectionServiceFocusLost() { 254 mEventLock[EVENT_CONNECTION_SERVICE_FOCUS_LOST].release(); 255 connectionServiceFocusReleased(); 256 } 257 setCreateVideoProvider(boolean createVideoProvider)258 public void setCreateVideoProvider(boolean createVideoProvider) { 259 mCreateVideoProvider = createVideoProvider; 260 } 261 262 /** Returns true if the given {@code event} is happened before the default timeout. */ waitForEvent(int event)263 public boolean waitForEvent(int event) { 264 if (event < 0 || event >= mEventLock.length) { 265 return false; 266 } 267 268 try { 269 return mEventLock[event].tryAcquire(DEFAULT_EVENT_TIMEOUT_MS, TimeUnit.MILLISECONDS); 270 } catch (InterruptedException e) { 271 // No interaction for the given event within the given timeout. 272 return false; 273 } 274 } 275 initializeSemaphore(int total)276 private static final Semaphore[] initializeSemaphore(int total) { 277 Semaphore[] locks = new Semaphore[total]; 278 for (int i = 0; i < total; i++) { 279 locks[i] = new Semaphore(0); 280 } 281 return locks; 282 } 283 } 284