ConnectionServiceFixture.java revision b7853c0b716f9cc9ae174d1ca4efaa118ef1740e
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 17package com.android.server.telecom.tests; 18 19import com.android.internal.telecom.IConnectionService; 20import com.android.internal.telecom.IConnectionServiceAdapter; 21import com.android.internal.telecom.IVideoProvider; 22import com.android.internal.telecom.RemoteServiceCallback; 23import com.android.server.telecom.Log; 24 25import junit.framework.TestCase; 26 27import org.mockito.Mockito; 28 29import android.content.ComponentName; 30import android.net.Uri; 31import android.os.Bundle; 32import android.os.IBinder; 33import android.os.IInterface; 34import android.os.RemoteException; 35import android.telecom.CallAudioState; 36import android.telecom.Conference; 37import android.telecom.Connection; 38import android.telecom.ConnectionRequest; 39import android.telecom.ConnectionService; 40import android.telecom.DisconnectCause; 41import android.telecom.ParcelableConference; 42import android.telecom.ParcelableConnection; 43import android.telecom.PhoneAccountHandle; 44import android.telecom.StatusHints; 45import android.telecom.TelecomManager; 46 47import java.lang.Override; 48import java.util.ArrayList; 49import java.util.HashMap; 50import java.util.HashSet; 51import java.util.List; 52import java.util.Map; 53import java.util.Set; 54 55/** 56 * Controls a test {@link IConnectionService} as would be provided by a source of connectivity 57 * to the Telecom framework. 58 */ 59public class ConnectionServiceFixture implements TestFixture<IConnectionService> { 60 static int INVALID_VIDEO_STATE = -1; 61 62 /** 63 * Implementation of ConnectionService that performs no-ops for tasks normally meant for 64 * Telephony and reports success back to Telecom 65 */ 66 public class FakeConnectionServiceDelegate extends ConnectionService { 67 int mVideoState = INVALID_VIDEO_STATE; 68 69 @Override 70 public Connection onCreateUnknownConnection( 71 PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) { 72 return new FakeConnection(request.getVideoState(), request.getAddress()); 73 } 74 75 @Override 76 public Connection onCreateIncomingConnection( 77 PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) { 78 return new FakeConnection( 79 mVideoState == INVALID_VIDEO_STATE ? request.getVideoState() : mVideoState, 80 request.getAddress()); 81 } 82 83 @Override 84 public Connection onCreateOutgoingConnection( 85 PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) { 86 return new FakeConnection(request.getVideoState(), request.getAddress()); 87 } 88 89 @Override 90 public void onConference(Connection cxn1, Connection cxn2) { 91 // Usually, this is implemented by something in Telephony, which does a bunch of radio 92 // work to conference the two connections together. Here we just short-cut that and 93 // declare them conferenced. 94 Conference fakeConference = new FakeConference(); 95 fakeConference.addConnection(cxn1); 96 fakeConference.addConnection(cxn2); 97 addConference(fakeConference); 98 } 99 } 100 101 public class FakeConnection extends Connection { 102 public FakeConnection(int videoState, Uri address) { 103 super(); 104 int capabilities = getConnectionCapabilities(); 105 capabilities |= CAPABILITY_MUTE; 106 capabilities |= CAPABILITY_SUPPORT_HOLD; 107 capabilities |= CAPABILITY_HOLD; 108 setVideoState(videoState); 109 setConnectionCapabilities(capabilities); 110 setActive(); 111 setAddress(address, TelecomManager.PRESENTATION_ALLOWED); 112 } 113 } 114 115 public class FakeConference extends Conference { 116 public FakeConference() { 117 super(null); 118 setConnectionCapabilities( 119 Connection.CAPABILITY_SUPPORT_HOLD 120 | Connection.CAPABILITY_HOLD 121 | Connection.CAPABILITY_MUTE 122 | Connection.CAPABILITY_MANAGE_CONFERENCE); 123 } 124 125 @Override 126 public void onMerge(Connection connection) { 127 // Do nothing besides inform the connection that it was merged into this conference. 128 connection.setConference(this); 129 } 130 } 131 132 public class FakeConnectionService extends IConnectionService.Stub { 133 134 @Override 135 public void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) 136 throws RemoteException { 137 if (!mConnectionServiceAdapters.add(adapter)) { 138 throw new RuntimeException("Adapter already added: " + adapter); 139 } 140 mConnectionServiceDelegateAdapter.addConnectionServiceAdapter(adapter); 141 } 142 143 @Override 144 public void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter) 145 throws RemoteException { 146 if (!mConnectionServiceAdapters.remove(adapter)) { 147 throw new RuntimeException("Adapter never added: " + adapter); 148 } 149 mConnectionServiceDelegateAdapter.removeConnectionServiceAdapter(adapter); 150 } 151 152 @Override 153 public void createConnection(PhoneAccountHandle connectionManagerPhoneAccount, 154 String id, 155 ConnectionRequest request, boolean isIncoming, boolean isUnknown) 156 throws RemoteException { 157 Log.i(ConnectionServiceFixture.this, "xoxox createConnection --> " + id); 158 159 if (mConnectionById.containsKey(id)) { 160 throw new RuntimeException("Connection already exists: " + id); 161 } 162 mLatestConnectionId = id; 163 ConnectionInfo c = new ConnectionInfo(); 164 c.connectionManagerPhoneAccount = connectionManagerPhoneAccount; 165 c.id = id; 166 c.request = request; 167 c.isIncoming = isIncoming; 168 c.isUnknown = isUnknown; 169 c.capabilities |= Connection.CAPABILITY_HOLD | Connection.CAPABILITY_SUPPORT_HOLD; 170 c.videoState = request.getVideoState(); 171 c.mockVideoProvider = new MockVideoProvider(); 172 c.videoProvider = c.mockVideoProvider.getInterface(); 173 mConnectionById.put(id, c); 174 mConnectionServiceDelegateAdapter.createConnection(connectionManagerPhoneAccount, 175 id, request, isIncoming, isUnknown); 176 } 177 178 @Override 179 public void abort(String callId) throws RemoteException { } 180 181 @Override 182 public void answerVideo(String callId, int videoState) throws RemoteException { } 183 184 @Override 185 public void answer(String callId) throws RemoteException { } 186 187 @Override 188 public void reject(String callId) throws RemoteException { } 189 190 @Override 191 public void rejectWithMessage(String callId, String message) throws RemoteException { } 192 193 @Override 194 public void disconnect(String callId) throws RemoteException { } 195 196 @Override 197 public void silence(String callId) throws RemoteException { } 198 199 @Override 200 public void hold(String callId) throws RemoteException { } 201 202 @Override 203 public void unhold(String callId) throws RemoteException { } 204 205 @Override 206 public void onCallAudioStateChanged(String activeCallId, CallAudioState audioState) 207 throws RemoteException { } 208 209 @Override 210 public void playDtmfTone(String callId, char digit) throws RemoteException { } 211 212 @Override 213 public void stopDtmfTone(String callId) throws RemoteException { } 214 215 @Override 216 public void conference(String conferenceCallId, String callId) throws RemoteException { 217 mConnectionServiceDelegateAdapter.conference(conferenceCallId, callId); 218 } 219 220 @Override 221 public void splitFromConference(String callId) throws RemoteException { } 222 223 @Override 224 public void mergeConference(String conferenceCallId) throws RemoteException { } 225 226 @Override 227 public void swapConference(String conferenceCallId) throws RemoteException { } 228 229 @Override 230 public void onPostDialContinue(String callId, boolean proceed) throws RemoteException { } 231 232 @Override 233 public IBinder asBinder() { 234 return this; 235 } 236 237 @Override 238 public IInterface queryLocalInterface(String descriptor) { 239 return this; 240 } 241 } 242 243 FakeConnectionServiceDelegate mConnectionServiceDelegate = 244 new FakeConnectionServiceDelegate(); 245 private IConnectionService mConnectionServiceDelegateAdapter = 246 IConnectionService.Stub.asInterface(mConnectionServiceDelegate.onBind(null)); 247 248 private IConnectionService.Stub mConnectionService = new FakeConnectionService(); 249 private IConnectionService.Stub mConnectionServiceSpy = Mockito.spy(mConnectionService); 250 251 public class ConnectionInfo { 252 PhoneAccountHandle connectionManagerPhoneAccount; 253 String id; 254 boolean ringing; 255 ConnectionRequest request; 256 boolean isIncoming; 257 boolean isUnknown; 258 int state; 259 int addressPresentation; 260 int capabilities; 261 StatusHints statusHints; 262 DisconnectCause disconnectCause; 263 String conferenceId; 264 String callerDisplayName; 265 int callerDisplayNamePresentation; 266 final List<String> conferenceableConnectionIds = new ArrayList<>(); 267 IVideoProvider videoProvider; 268 Connection.VideoProvider videoProviderImpl; 269 MockVideoProvider mockVideoProvider; 270 int videoState; 271 boolean isVoipAudioMode; 272 Bundle extras; 273 } 274 275 public class ConferenceInfo { 276 PhoneAccountHandle phoneAccount; 277 int state; 278 int capabilities; 279 final List<String> connectionIds = new ArrayList<>(); 280 IVideoProvider videoProvider; 281 int videoState; 282 long connectTimeMillis; 283 StatusHints statusHints; 284 Bundle extras; 285 } 286 287 public String mLatestConnectionId; 288 public final Set<IConnectionServiceAdapter> mConnectionServiceAdapters = new HashSet<>(); 289 public final Map<String, ConnectionInfo> mConnectionById = new HashMap<>(); 290 public final Map<String, ConferenceInfo> mConferenceById = new HashMap<>(); 291 public final List<ComponentName> mRemoteConnectionServiceNames = new ArrayList<>(); 292 public final List<IBinder> mRemoteConnectionServices = new ArrayList<>(); 293 294 public ConnectionServiceFixture() throws Exception { } 295 296 @Override 297 public IConnectionService getTestDouble() { 298 return mConnectionServiceSpy; 299 } 300 301 public void sendHandleCreateConnectionComplete(String id) throws Exception { 302 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 303 a.handleCreateConnectionComplete( 304 id, 305 mConnectionById.get(id).request, 306 parcelable(mConnectionById.get(id))); 307 } 308 } 309 310 public void sendSetActive(String id) throws Exception { 311 mConnectionById.get(id).state = Connection.STATE_ACTIVE; 312 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 313 a.setActive(id); 314 } 315 } 316 317 public void sendSetRinging(String id) throws Exception { 318 mConnectionById.get(id).state = Connection.STATE_RINGING; 319 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 320 a.setRinging(id); 321 } 322 } 323 324 public void sendSetDialing(String id) throws Exception { 325 mConnectionById.get(id).state = Connection.STATE_DIALING; 326 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 327 a.setDialing(id); 328 } 329 } 330 331 public void sendSetDisconnected(String id, int disconnectCause) throws Exception { 332 mConnectionById.get(id).state = Connection.STATE_DISCONNECTED; 333 mConnectionById.get(id).disconnectCause = new DisconnectCause(disconnectCause); 334 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 335 a.setDisconnected(id, mConnectionById.get(id).disconnectCause); 336 } 337 } 338 339 public void sendSetOnHold(String id) throws Exception { 340 mConnectionById.get(id).state = Connection.STATE_HOLDING; 341 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 342 a.setOnHold(id); 343 } 344 } 345 346 public void sendSetRingbackRequested(String id) throws Exception { 347 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 348 a.setRingbackRequested(id, mConnectionById.get(id).ringing); 349 } 350 } 351 352 public void sendSetConnectionCapabilities(String id) throws Exception { 353 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 354 a.setConnectionCapabilities(id, mConnectionById.get(id).capabilities); 355 } 356 } 357 358 public void sendSetIsConferenced(String id) throws Exception { 359 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 360 a.setIsConferenced(id, mConnectionById.get(id).conferenceId); 361 } 362 } 363 364 public void sendAddConferenceCall(String id) throws Exception { 365 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 366 a.addConferenceCall(id, parcelable(mConferenceById.get(id))); 367 } 368 } 369 370 public void sendRemoveCall(String id) throws Exception { 371 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 372 a.removeCall(id); 373 } 374 } 375 376 public void sendOnPostDialWait(String id, String remaining) throws Exception { 377 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 378 a.onPostDialWait(id, remaining); 379 } 380 } 381 382 public void sendOnPostDialChar(String id, char nextChar) throws Exception { 383 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 384 a.onPostDialChar(id, nextChar); 385 } 386 } 387 388 public void sendQueryRemoteConnectionServices() throws Exception { 389 mRemoteConnectionServices.clear(); 390 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 391 a.queryRemoteConnectionServices(new RemoteServiceCallback.Stub() { 392 @Override 393 public void onError() throws RemoteException { 394 throw new RuntimeException(); 395 } 396 397 @Override 398 public void onResult( 399 List<ComponentName> names, 400 List<IBinder> services) 401 throws RemoteException { 402 TestCase.assertEquals(names.size(), services.size()); 403 mRemoteConnectionServiceNames.addAll(names); 404 mRemoteConnectionServices.addAll(services); 405 } 406 407 @Override 408 public IBinder asBinder() { 409 return this; 410 } 411 }); 412 } 413 } 414 415 public void sendSetVideoProvider(String id) throws Exception { 416 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 417 a.setVideoProvider(id, mConnectionById.get(id).videoProvider); 418 } 419 } 420 421 public void sendSetVideoState(String id) throws Exception { 422 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 423 a.setVideoState(id, mConnectionById.get(id).videoState); 424 } 425 } 426 427 public void sendSetIsVoipAudioMode(String id) throws Exception { 428 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 429 a.setIsVoipAudioMode(id, mConnectionById.get(id).isVoipAudioMode); 430 } 431 } 432 433 public void sendSetStatusHints(String id) throws Exception { 434 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 435 a.setStatusHints(id, mConnectionById.get(id).statusHints); 436 } 437 } 438 439 public void sendSetAddress(String id) throws Exception { 440 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 441 a.setAddress( 442 id, 443 mConnectionById.get(id).request.getAddress(), 444 mConnectionById.get(id).addressPresentation); 445 } 446 } 447 448 public void sendSetCallerDisplayName(String id) throws Exception { 449 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 450 a.setCallerDisplayName( 451 id, 452 mConnectionById.get(id).callerDisplayName, 453 mConnectionById.get(id).callerDisplayNamePresentation); 454 } 455 } 456 457 public void sendSetConferenceableConnections(String id) throws Exception { 458 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 459 a.setConferenceableConnections(id, mConnectionById.get(id).conferenceableConnectionIds); 460 } 461 } 462 463 public void sendAddExistingConnection(String id) throws Exception { 464 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 465 a.addExistingConnection(id, parcelable(mConnectionById.get(id))); 466 } 467 } 468 469 private ParcelableConference parcelable(ConferenceInfo c) { 470 return new ParcelableConference( 471 c.phoneAccount, 472 c.state, 473 c.capabilities, 474 c.connectionIds, 475 c.videoProvider, 476 c.videoState, 477 c.connectTimeMillis, 478 c.statusHints, 479 c.extras); 480 } 481 482 private ParcelableConnection parcelable(ConnectionInfo c) { 483 return new ParcelableConnection( 484 c.request.getAccountHandle(), 485 c.state, 486 c.capabilities, 487 c.request.getAddress(), 488 c.addressPresentation, 489 c.callerDisplayName, 490 c.callerDisplayNamePresentation, 491 c.videoProvider, 492 c.videoState, 493 false, /* ringback requested */ 494 false, /* voip audio mode */ 495 0, /* Connect Time for conf call on this connection */ 496 c.statusHints, 497 c.disconnectCause, 498 c.conferenceableConnectionIds, 499 c.extras); 500 } 501} 502