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 com.android.server.telecom.tests; 18 19 import com.android.internal.telecom.IConnectionService; 20 import com.android.internal.telecom.IConnectionServiceAdapter; 21 import com.android.internal.telecom.IVideoProvider; 22 import com.android.internal.telecom.RemoteServiceCallback; 23 import com.android.server.telecom.Log; 24 25 import junit.framework.TestCase; 26 27 import org.mockito.Mockito; 28 29 import android.content.ComponentName; 30 import android.os.Bundle; 31 import android.os.IBinder; 32 import android.os.IInterface; 33 import android.os.RemoteException; 34 import android.telecom.CallAudioState; 35 import android.telecom.Connection; 36 import android.telecom.ConnectionRequest; 37 import android.telecom.DisconnectCause; 38 import android.telecom.ParcelableConference; 39 import android.telecom.ParcelableConnection; 40 import android.telecom.PhoneAccountHandle; 41 import android.telecom.StatusHints; 42 43 import java.util.ArrayList; 44 import java.util.HashMap; 45 import java.util.HashSet; 46 import java.util.List; 47 import java.util.Map; 48 import java.util.Set; 49 50 import static org.mockito.Matchers.any; 51 52 /** 53 * Controls a test {@link IConnectionService} as would be provided by a source of connectivity 54 * to the Telecom framework. 55 */ 56 public class ConnectionServiceFixture implements TestFixture<IConnectionService> { 57 58 public class FakeConnectionService extends IConnectionService.Stub { 59 60 @Override 61 public void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) 62 throws RemoteException { 63 if (!mConnectionServiceAdapters.add(adapter)) { 64 throw new RuntimeException("Adapter already added: " + adapter); 65 } 66 } 67 68 @Override 69 public void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter) 70 throws RemoteException { 71 if (!mConnectionServiceAdapters.remove(adapter)) { 72 throw new RuntimeException("Adapter never added: " + adapter); 73 } 74 } 75 76 @Override 77 public void createConnection(PhoneAccountHandle connectionManagerPhoneAccount, 78 String id, 79 ConnectionRequest request, boolean isIncoming, boolean isUnknown) 80 throws RemoteException { 81 Log.i(ConnectionServiceFixture.this, "xoxox createConnection --> " + id); 82 83 if (mConnectionById.containsKey(id)) { 84 throw new RuntimeException("Connection already exists: " + id); 85 } 86 mLatestConnectionId = id; 87 ConnectionInfo c = new ConnectionInfo(); 88 c.connectionManagerPhoneAccount = connectionManagerPhoneAccount; 89 c.id = id; 90 c.request = request; 91 c.isIncoming = isIncoming; 92 c.isUnknown = isUnknown; 93 c.capabilities |= Connection.CAPABILITY_HOLD | Connection.CAPABILITY_SUPPORT_HOLD; 94 mConnectionById.put(id, c); 95 } 96 97 @Override 98 public void abort(String callId) throws RemoteException { } 99 100 @Override 101 public void answerVideo(String callId, int videoState) throws RemoteException { } 102 103 @Override 104 public void answer(String callId) throws RemoteException { } 105 106 @Override 107 public void reject(String callId) throws RemoteException { } 108 109 @Override 110 public void disconnect(String callId) throws RemoteException { } 111 112 @Override 113 public void hold(String callId) throws RemoteException { } 114 115 @Override 116 public void unhold(String callId) throws RemoteException { } 117 118 @Override 119 public void onCallAudioStateChanged(String activeCallId, CallAudioState audioState) 120 throws RemoteException { } 121 122 @Override 123 public void playDtmfTone(String callId, char digit) throws RemoteException { } 124 125 @Override 126 public void stopDtmfTone(String callId) throws RemoteException { } 127 128 @Override 129 public void conference(String conferenceCallId, String callId) throws RemoteException { } 130 131 @Override 132 public void splitFromConference(String callId) throws RemoteException { } 133 134 @Override 135 public void mergeConference(String conferenceCallId) throws RemoteException { } 136 137 @Override 138 public void swapConference(String conferenceCallId) throws RemoteException { } 139 140 @Override 141 public void onPostDialContinue(String callId, boolean proceed) throws RemoteException { } 142 143 @Override 144 public IBinder asBinder() { 145 return this; 146 } 147 148 @Override 149 public IInterface queryLocalInterface(String descriptor) { 150 return this; 151 } 152 }; 153 154 private IConnectionService.Stub mConnectionService = new FakeConnectionService(); 155 private IConnectionService.Stub mConnectionServiceSpy = Mockito.spy(mConnectionService); 156 157 public class ConnectionInfo { 158 PhoneAccountHandle connectionManagerPhoneAccount; 159 String id; 160 boolean ringing; 161 ConnectionRequest request; 162 boolean isIncoming; 163 boolean isUnknown; 164 int state; 165 int addressPresentation; 166 int capabilities; 167 StatusHints statusHints; 168 DisconnectCause disconnectCause; 169 String conferenceId; 170 String callerDisplayName; 171 int callerDisplayNamePresentation; 172 final List<String> conferenceableConnectionIds = new ArrayList<>(); 173 IVideoProvider videoProvider; 174 int videoState; 175 boolean isVoipAudioMode; 176 Bundle extras; 177 } 178 179 public class ConferenceInfo { 180 PhoneAccountHandle phoneAccount; 181 int state; 182 int capabilities; 183 final List<String> connectionIds = new ArrayList<>(); 184 IVideoProvider videoProvider; 185 int videoState; 186 long connectTimeMillis; 187 StatusHints statusHints; 188 Bundle extras; 189 } 190 191 public String mLatestConnectionId; 192 public final Set<IConnectionServiceAdapter> mConnectionServiceAdapters = new HashSet<>(); 193 public final Map<String, ConnectionInfo> mConnectionById = new HashMap<>(); 194 public final Map<String, ConferenceInfo> mConferenceById = new HashMap<>(); 195 public final List<ComponentName> mRemoteConnectionServiceNames = new ArrayList<>(); 196 public final List<IBinder> mRemoteConnectionServices = new ArrayList<>(); 197 198 public ConnectionServiceFixture() throws Exception { } 199 200 @Override 201 public IConnectionService getTestDouble() { 202 return mConnectionServiceSpy; 203 } 204 205 public void sendHandleCreateConnectionComplete(String id) throws Exception { 206 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 207 a.handleCreateConnectionComplete( 208 id, 209 mConnectionById.get(id).request, 210 parcelable(mConnectionById.get(id))); 211 } 212 } 213 214 public void sendSetActive(String id) throws Exception { 215 mConnectionById.get(id).state = Connection.STATE_ACTIVE; 216 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 217 a.setActive(id); 218 } 219 } 220 221 public void sendSetRinging(String id) throws Exception { 222 mConnectionById.get(id).state = Connection.STATE_RINGING; 223 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 224 a.setRinging(id); 225 } 226 } 227 228 public void sendSetDialing(String id) throws Exception { 229 mConnectionById.get(id).state = Connection.STATE_DIALING; 230 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 231 a.setDialing(id); 232 } 233 } 234 235 public void sendSetDisconnected(String id, int disconnectCause) throws Exception { 236 mConnectionById.get(id).state = Connection.STATE_DISCONNECTED; 237 mConnectionById.get(id).disconnectCause = new DisconnectCause(disconnectCause); 238 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 239 a.setDisconnected(id, mConnectionById.get(id).disconnectCause); 240 } 241 } 242 243 public void sendSetOnHold(String id) throws Exception { 244 mConnectionById.get(id).state = Connection.STATE_HOLDING; 245 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 246 a.setOnHold(id); 247 } 248 } 249 250 public void sendSetRingbackRequested(String id) throws Exception { 251 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 252 a.setRingbackRequested(id, mConnectionById.get(id).ringing); 253 } 254 } 255 256 public void sendSetConnectionCapabilities(String id) throws Exception { 257 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 258 a.setConnectionCapabilities(id, mConnectionById.get(id).capabilities); 259 } 260 } 261 262 public void sendSetIsConferenced(String id) throws Exception { 263 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 264 a.setIsConferenced(id, mConnectionById.get(id).conferenceId); 265 } 266 } 267 268 public void sendAddConferenceCall(String id) throws Exception { 269 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 270 a.addConferenceCall(id, parcelable(mConferenceById.get(id))); 271 } 272 } 273 274 public void sendRemoveCall(String id) throws Exception { 275 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 276 a.removeCall(id); 277 } 278 } 279 280 public void sendOnPostDialWait(String id, String remaining) throws Exception { 281 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 282 a.onPostDialWait(id, remaining); 283 } 284 } 285 286 public void sendOnPostDialChar(String id, char nextChar) throws Exception { 287 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 288 a.onPostDialChar(id, nextChar); 289 } 290 } 291 292 public void sendQueryRemoteConnectionServices() throws Exception { 293 mRemoteConnectionServices.clear(); 294 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 295 a.queryRemoteConnectionServices(new RemoteServiceCallback.Stub() { 296 @Override 297 public void onError() throws RemoteException { 298 throw new RuntimeException(); 299 } 300 301 @Override 302 public void onResult( 303 List<ComponentName> names, 304 List<IBinder> services) 305 throws RemoteException { 306 TestCase.assertEquals(names.size(), services.size()); 307 mRemoteConnectionServiceNames.addAll(names); 308 mRemoteConnectionServices.addAll(services); 309 } 310 311 @Override 312 public IBinder asBinder() { 313 return this; 314 } 315 }); 316 } 317 } 318 319 public void sendSetVideoProvider(String id) throws Exception { 320 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 321 a.setVideoProvider(id, mConnectionById.get(id).videoProvider); 322 } 323 } 324 325 public void sendSetVideoState(String id) throws Exception { 326 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 327 a.setVideoState(id, mConnectionById.get(id).videoState); 328 } 329 } 330 331 public void sendSetIsVoipAudioMode(String id) throws Exception { 332 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 333 a.setIsVoipAudioMode(id, mConnectionById.get(id).isVoipAudioMode); 334 } 335 } 336 337 public void sendSetStatusHints(String id) throws Exception { 338 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 339 a.setStatusHints(id, mConnectionById.get(id).statusHints); 340 } 341 } 342 343 public void sendSetAddress(String id) throws Exception { 344 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 345 a.setAddress( 346 id, 347 mConnectionById.get(id).request.getAddress(), 348 mConnectionById.get(id).addressPresentation); 349 } 350 } 351 352 public void sendSetCallerDisplayName(String id) throws Exception { 353 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 354 a.setCallerDisplayName( 355 id, 356 mConnectionById.get(id).callerDisplayName, 357 mConnectionById.get(id).callerDisplayNamePresentation); 358 } 359 } 360 361 public void sendSetConferenceableConnections(String id) throws Exception { 362 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 363 a.setConferenceableConnections(id, mConnectionById.get(id).conferenceableConnectionIds); 364 } 365 } 366 367 public void sendAddExistingConnection(String id) throws Exception { 368 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 369 a.addExistingConnection(id, parcelable(mConnectionById.get(id))); 370 } 371 } 372 373 private ParcelableConference parcelable(ConferenceInfo c) { 374 return new ParcelableConference( 375 c.phoneAccount, 376 c.state, 377 c.capabilities, 378 c.connectionIds, 379 c.videoProvider, 380 c.videoState, 381 c.connectTimeMillis, 382 c.statusHints, 383 c.extras); 384 } 385 386 private ParcelableConnection parcelable(ConnectionInfo c) { 387 return new ParcelableConnection( 388 c.request.getAccountHandle(), 389 c.state, 390 c.capabilities, 391 c.request.getAddress(), 392 c.addressPresentation, 393 c.callerDisplayName, 394 c.callerDisplayNamePresentation, 395 c.videoProvider, 396 c.videoState, 397 false, /* ringback requested */ 398 false, /* voip audio mode */ 399 0, /* Connect Time for conf call on this connection */ 400 c.statusHints, 401 c.disconnectCause, 402 c.conferenceableConnectionIds, 403 c.extras); 404 } 405 } 406