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