1 /* 2 * Copyright (C) 2021 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.app; 18 19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; 20 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; 21 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 22 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions; 23 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; 24 import static com.android.server.app.GameServiceProviderInstanceImplTest.FakeGameService.GameServiceState; 25 26 import static com.google.common.collect.Iterables.getOnlyElement; 27 import static com.google.common.truth.Truth.assertThat; 28 29 import static org.junit.Assert.assertEquals; 30 import static org.junit.Assert.assertNotNull; 31 import static org.mockito.ArgumentMatchers.any; 32 import static org.mockito.ArgumentMatchers.anyBoolean; 33 import static org.mockito.ArgumentMatchers.anyInt; 34 import static org.mockito.ArgumentMatchers.anyString; 35 import static org.mockito.ArgumentMatchers.eq; 36 import static org.mockito.Mockito.never; 37 38 import android.annotation.Nullable; 39 import android.app.ActivityManager.RunningTaskInfo; 40 import android.app.ActivityManagerInternal; 41 import android.app.ActivityTaskManager; 42 import android.app.IActivityManager; 43 import android.app.IActivityTaskManager; 44 import android.app.IProcessObserver; 45 import android.app.ITaskStackListener; 46 import android.content.ComponentName; 47 import android.content.Context; 48 import android.content.ContextWrapper; 49 import android.content.Intent; 50 import android.content.pm.PackageManager; 51 import android.graphics.Bitmap; 52 import android.graphics.Canvas; 53 import android.graphics.Color; 54 import android.graphics.Paint; 55 import android.graphics.Picture; 56 import android.graphics.Rect; 57 import android.net.Uri; 58 import android.os.RemoteException; 59 import android.os.UserHandle; 60 import android.platform.test.annotations.Presubmit; 61 import android.service.games.CreateGameSessionRequest; 62 import android.service.games.CreateGameSessionResult; 63 import android.service.games.GameScreenshotResult; 64 import android.service.games.GameSessionViewHostConfiguration; 65 import android.service.games.GameStartedEvent; 66 import android.service.games.IGameService; 67 import android.service.games.IGameServiceController; 68 import android.service.games.IGameSession; 69 import android.service.games.IGameSessionController; 70 import android.service.games.IGameSessionService; 71 import android.view.SurfaceControl; 72 import android.view.SurfaceControlViewHost.SurfacePackage; 73 74 import androidx.test.filters.SmallTest; 75 import androidx.test.platform.app.InstrumentationRegistry; 76 import androidx.test.runner.AndroidJUnit4; 77 78 import com.android.internal.infra.AndroidFuture; 79 import com.android.internal.util.ConcurrentUtils; 80 import com.android.internal.util.FunctionalUtils.ThrowingConsumer; 81 import com.android.internal.util.Preconditions; 82 import com.android.internal.util.ScreenshotHelper; 83 import com.android.server.wm.ActivityTaskManagerInternal; 84 import com.android.server.wm.WindowManagerInternal; 85 import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener; 86 import com.android.server.wm.WindowManagerService; 87 88 import org.junit.After; 89 import org.junit.Before; 90 import org.junit.Test; 91 import org.junit.runner.RunWith; 92 import org.mockito.Mock; 93 import org.mockito.Mockito; 94 import org.mockito.MockitoSession; 95 import org.mockito.quality.Strictness; 96 97 import java.util.ArrayList; 98 import java.util.HashMap; 99 import java.util.function.Consumer; 100 101 102 /** 103 * Unit tests for the {@link GameServiceProviderInstanceImpl}. 104 */ 105 @RunWith(AndroidJUnit4.class) 106 @SmallTest 107 @Presubmit 108 public final class GameServiceProviderInstanceImplTest { 109 110 private static final GameSessionViewHostConfiguration 111 DEFAULT_GAME_SESSION_VIEW_HOST_CONFIGURATION = 112 new GameSessionViewHostConfiguration(1, 500, 800); 113 private static final int USER_ID = 10; 114 private static final String APP_A_PACKAGE = "com.package.app.a"; 115 private static final ComponentName APP_A_MAIN_ACTIVITY = 116 new ComponentName(APP_A_PACKAGE, "com.package.app.a.MainActivity"); 117 118 private static final String GAME_A_PACKAGE = "com.package.game.a"; 119 private static final ComponentName GAME_A_MAIN_ACTIVITY = 120 new ComponentName(GAME_A_PACKAGE, "com.package.game.a.MainActivity"); 121 122 private static final String GAME_B_PACKAGE = "com.package.game.b"; 123 private static final ComponentName GAME_B_MAIN_ACTIVITY = 124 new ComponentName(GAME_B_PACKAGE, "com.package.game.b.MainActivity"); 125 126 127 private static final Bitmap TEST_BITMAP; 128 129 static { 130 Picture picture = new Picture(); 131 Canvas canvas = picture.beginRecording(200, 100); 132 Paint p = new Paint(); 133 p.setColor(Color.BLACK); 134 canvas.drawCircle(10, 10, 10, p); picture.endRecording()135 picture.endRecording(); 136 TEST_BITMAP = Bitmap.createBitmap(picture); 137 } 138 139 private MockitoSession mMockingSession; 140 private GameServiceProviderInstance mGameServiceProviderInstance; 141 @Mock 142 private ActivityManagerInternal mMockActivityManagerInternal; 143 @Mock 144 private IActivityTaskManager mMockActivityTaskManager; 145 @Mock 146 private WindowManagerService mMockWindowManagerService; 147 @Mock 148 private WindowManagerInternal mMockWindowManagerInternal; 149 @Mock 150 private ActivityTaskManagerInternal mActivityTaskManagerInternal; 151 @Mock 152 private IActivityManager mMockActivityManager; 153 @Mock 154 private ScreenshotHelper mMockScreenshotHelper; 155 private MockContext mMockContext; 156 private FakeGameClassifier mFakeGameClassifier; 157 private FakeGameService mFakeGameService; 158 private FakeServiceConnector<IGameService> mFakeGameServiceConnector; 159 private FakeGameSessionService mFakeGameSessionService; 160 private FakeServiceConnector<IGameSessionService> mFakeGameSessionServiceConnector; 161 private ArrayList<ITaskStackListener> mTaskStackListeners; 162 private ArrayList<IProcessObserver> mProcessObservers; 163 private ArrayList<TaskSystemBarsListener> mTaskSystemBarsListeners; 164 private ArrayList<RunningTaskInfo> mRunningTaskInfos; 165 166 @Mock 167 private PackageManager mMockPackageManager; 168 169 @Before setUp()170 public void setUp() throws PackageManager.NameNotFoundException, RemoteException { 171 mMockingSession = mockitoSession() 172 .initMocks(this) 173 .strictness(Strictness.LENIENT) 174 .startMocking(); 175 176 mMockContext = new MockContext(InstrumentationRegistry.getInstrumentation().getContext()); 177 178 mFakeGameClassifier = new FakeGameClassifier(); 179 mFakeGameClassifier.recordGamePackage(GAME_A_PACKAGE); 180 mFakeGameClassifier.recordGamePackage(GAME_B_PACKAGE); 181 182 mFakeGameService = new FakeGameService(); 183 mFakeGameServiceConnector = new FakeServiceConnector<>(mFakeGameService); 184 mFakeGameSessionService = new FakeGameSessionService(); 185 mFakeGameSessionServiceConnector = new FakeServiceConnector<>(mFakeGameSessionService); 186 187 mTaskStackListeners = new ArrayList<>(); 188 doAnswer(invocation -> { 189 mTaskStackListeners.add(invocation.getArgument(0)); 190 return null; 191 }).when(mMockActivityTaskManager).registerTaskStackListener(any()); 192 doAnswer(invocation -> { 193 mTaskStackListeners.remove(invocation.getArgument(0)); 194 return null; 195 }).when(mMockActivityTaskManager).unregisterTaskStackListener(any()); 196 197 mProcessObservers = new ArrayList<>(); 198 doAnswer(invocation -> { 199 mProcessObservers.add(invocation.getArgument(0)); 200 return null; 201 }).when(mMockActivityManager).registerProcessObserver(any()); 202 doAnswer(invocation -> { 203 mProcessObservers.remove(invocation.getArgument(0)); 204 return null; 205 }).when(mMockActivityManager).unregisterProcessObserver(any()); 206 207 mTaskSystemBarsListeners = new ArrayList<>(); 208 doAnswer(invocation -> { 209 mTaskSystemBarsListeners.add(invocation.getArgument(0)); 210 return null; 211 }).when(mMockWindowManagerInternal).registerTaskSystemBarsListener(any()); 212 doAnswer(invocation -> { 213 mTaskSystemBarsListeners.remove(invocation.getArgument(0)); 214 return null; 215 }).when(mMockWindowManagerInternal).unregisterTaskSystemBarsListener(any()); 216 217 mRunningTaskInfos = new ArrayList<>(); 218 when(mMockActivityTaskManager.getTasks(anyInt(), anyBoolean(), anyBoolean(), anyInt())) 219 .thenReturn(mRunningTaskInfos); 220 221 222 final UserHandle userHandle = new UserHandle(USER_ID); 223 mGameServiceProviderInstance = new GameServiceProviderInstanceImpl( 224 userHandle, 225 ConcurrentUtils.DIRECT_EXECUTOR, 226 mMockContext, 227 new GameTaskInfoProvider(userHandle, mMockActivityTaskManager, mFakeGameClassifier), 228 mMockActivityManager, 229 mMockActivityManagerInternal, 230 mMockActivityTaskManager, 231 mMockWindowManagerService, 232 mMockWindowManagerInternal, 233 mActivityTaskManagerInternal, 234 mFakeGameServiceConnector, 235 mFakeGameSessionServiceConnector, 236 mMockScreenshotHelper); 237 } 238 239 @After tearDown()240 public void tearDown() { 241 mMockingSession.finishMocking(); 242 } 243 244 @Test start_startsGameSession()245 public void start_startsGameSession() throws Exception { 246 mGameServiceProviderInstance.start(); 247 248 assertThat(mFakeGameService.getState()).isEqualTo(GameServiceState.CONNECTED); 249 assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue(); 250 assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1); 251 assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0); 252 } 253 254 @Test start_multipleTimes_startsGameSessionOnce()255 public void start_multipleTimes_startsGameSessionOnce() throws Exception { 256 mGameServiceProviderInstance.start(); 257 mGameServiceProviderInstance.start(); 258 259 assertThat(mFakeGameService.getState()).isEqualTo(GameServiceState.CONNECTED); 260 assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue(); 261 assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1); 262 assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0); 263 } 264 265 @Test stop_neverStarted_doesNothing()266 public void stop_neverStarted_doesNothing() throws Exception { 267 mGameServiceProviderInstance.stop(); 268 269 270 assertThat(mFakeGameService.getState()).isEqualTo(GameServiceState.DISCONNECTED); 271 assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(0); 272 assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0); 273 } 274 275 @Test startAndStop_startsAndStopsGameSession()276 public void startAndStop_startsAndStopsGameSession() throws Exception { 277 mGameServiceProviderInstance.start(); 278 mGameServiceProviderInstance.stop(); 279 280 assertThat(mFakeGameService.getState()).isEqualTo(GameServiceState.DISCONNECTED); 281 assertThat(mFakeGameService.getConnectedCount()).isEqualTo(1); 282 assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse(); 283 assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1); 284 assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0); 285 } 286 287 @Test startAndStop_multipleTimes_startsAndStopsGameSessionMultipleTimes()288 public void startAndStop_multipleTimes_startsAndStopsGameSessionMultipleTimes() 289 throws Exception { 290 mGameServiceProviderInstance.start(); 291 mGameServiceProviderInstance.stop(); 292 mGameServiceProviderInstance.start(); 293 mGameServiceProviderInstance.stop(); 294 295 assertThat(mFakeGameService.getState()).isEqualTo(GameServiceState.DISCONNECTED); 296 assertThat(mFakeGameService.getConnectedCount()).isEqualTo(2); 297 assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse(); 298 assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(2); 299 assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0); 300 } 301 302 @Test stop_stopMultipleTimes_stopsGameSessionOnce()303 public void stop_stopMultipleTimes_stopsGameSessionOnce() throws Exception { 304 mGameServiceProviderInstance.start(); 305 mGameServiceProviderInstance.stop(); 306 mGameServiceProviderInstance.stop(); 307 308 assertThat(mFakeGameService.getState()).isEqualTo(GameServiceState.DISCONNECTED); 309 assertThat(mFakeGameService.getConnectedCount()).isEqualTo(1); 310 assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse(); 311 assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1); 312 assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0); 313 } 314 315 @Test gameTaskStarted_neverStarted_doesNothing()316 public void gameTaskStarted_neverStarted_doesNothing() throws Exception { 317 dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY); 318 319 assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(0); 320 assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0); 321 } 322 323 @Test gameTaskRemoved_neverStarted_doesNothing()324 public void gameTaskRemoved_neverStarted_doesNothing() throws Exception { 325 dispatchTaskRemoved(10); 326 327 assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(0); 328 assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0); 329 } 330 331 @Test gameTaskStarted_afterStopped_doesNotSendGameStartedEvent()332 public void gameTaskStarted_afterStopped_doesNotSendGameStartedEvent() throws Exception { 333 mGameServiceProviderInstance.start(); 334 mGameServiceProviderInstance.stop(); 335 dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY); 336 337 assertThat(mFakeGameService.getGameStartedEvents()).isEmpty(); 338 } 339 340 @Test appTaskStarted_doesNotSendGameStartedEvent()341 public void appTaskStarted_doesNotSendGameStartedEvent() throws Exception { 342 mGameServiceProviderInstance.start(); 343 dispatchTaskCreated(10, APP_A_MAIN_ACTIVITY); 344 345 assertThat(mFakeGameService.getGameStartedEvents()).isEmpty(); 346 } 347 348 @Test taskStarted_nullComponentName_ignoresAndDoesNotCrash()349 public void taskStarted_nullComponentName_ignoresAndDoesNotCrash() throws Exception { 350 mGameServiceProviderInstance.start(); 351 dispatchTaskCreated(10, null); 352 353 assertThat(mFakeGameService.getGameStartedEvents()).isEmpty(); 354 } 355 356 @Test gameSessionRequested_withoutTaskDispatch_doesNotCrashAndDoesNotCreateGameSession()357 public void gameSessionRequested_withoutTaskDispatch_doesNotCrashAndDoesNotCreateGameSession() 358 throws Exception { 359 mGameServiceProviderInstance.start(); 360 361 mFakeGameService.requestCreateGameSession(10); 362 363 assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).isEmpty(); 364 } 365 366 @Test gameTaskStarted_noSessionRequest_callsStartGame()367 public void gameTaskStarted_noSessionRequest_callsStartGame() throws Exception { 368 mGameServiceProviderInstance.start(); 369 dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY); 370 371 GameStartedEvent expectedGameStartedEvent = new GameStartedEvent(10, GAME_A_PACKAGE); 372 assertThat(mFakeGameService.getGameStartedEvents()) 373 .containsExactly(expectedGameStartedEvent).inOrder(); 374 } 375 376 @Test gameTaskStarted_requestToCreateGameSessionIncludesTaskConfiguration()377 public void gameTaskStarted_requestToCreateGameSessionIncludesTaskConfiguration() 378 throws Exception { 379 mGameServiceProviderInstance.start(); 380 startTask(10, GAME_A_MAIN_ACTIVITY); 381 382 mFakeGameService.requestCreateGameSession(10); 383 384 FakeGameSessionService.CapturedCreateInvocation capturedCreateInvocation = 385 getOnlyElement(mFakeGameSessionService.getCapturedCreateInvocations()); 386 assertThat(capturedCreateInvocation.mGameSessionViewHostConfiguration) 387 .isEqualTo(DEFAULT_GAME_SESSION_VIEW_HOST_CONFIGURATION); 388 } 389 390 @Test gameTaskStarted_failsToDetermineTaskOverlayConfiguration_gameSessionNotCreated()391 public void gameTaskStarted_failsToDetermineTaskOverlayConfiguration_gameSessionNotCreated() 392 throws Exception { 393 mGameServiceProviderInstance.start(); 394 dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY); 395 396 mFakeGameService.requestCreateGameSession(10); 397 398 assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).isEmpty(); 399 } 400 401 @Test gameTaskStartedAndSessionRequested_createsGameSession()402 public void gameTaskStartedAndSessionRequested_createsGameSession() throws Exception { 403 mGameServiceProviderInstance.start(); 404 startTask(10, GAME_A_MAIN_ACTIVITY); 405 mFakeGameService.requestCreateGameSession(10); 406 407 FakeGameSession gameSession10 = new FakeGameSession(); 408 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 409 mFakeGameSessionService.removePendingFutureForTaskId(10) 410 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 411 412 assertThat(gameSession10.mIsDestroyed).isFalse(); 413 assertThat(gameSession10.mIsFocused).isFalse(); 414 } 415 416 @Test gameTaskStartedAndSessionRequested_secondSessionRequest_ignoredAndDoesNotCrash()417 public void gameTaskStartedAndSessionRequested_secondSessionRequest_ignoredAndDoesNotCrash() 418 throws Exception { 419 mGameServiceProviderInstance.start(); 420 startTask(10, GAME_A_MAIN_ACTIVITY); 421 422 mFakeGameService.requestCreateGameSession(10); 423 mFakeGameService.requestCreateGameSession(10); 424 425 CreateGameSessionRequest expectedCreateGameSessionRequest = new CreateGameSessionRequest(10, 426 GAME_A_PACKAGE); 427 assertThat(getOnlyElement( 428 mFakeGameSessionService.getCapturedCreateInvocations()).mCreateGameSessionRequest) 429 .isEqualTo(expectedCreateGameSessionRequest); 430 } 431 432 @Test gameSessionSuccessfullyCreated_createsTaskOverlay()433 public void gameSessionSuccessfullyCreated_createsTaskOverlay() throws Exception { 434 mGameServiceProviderInstance.start(); 435 startTask(10, GAME_A_MAIN_ACTIVITY); 436 mFakeGameService.requestCreateGameSession(10); 437 438 FakeGameSession gameSession10 = new FakeGameSession(); 439 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 440 mFakeGameSessionService.removePendingFutureForTaskId(10) 441 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 442 443 verify(mMockWindowManagerInternal).addTrustedTaskOverlay(eq(10), eq(mockSurfacePackage10)); 444 } 445 446 @Test gameProcessStopped_soleProcess_destroysGameSession()447 public void gameProcessStopped_soleProcess_destroysGameSession() throws Exception { 448 int gameProcessId = 1000; 449 450 mGameServiceProviderInstance.start(); 451 452 startTask(10, GAME_A_MAIN_ACTIVITY); 453 startProcessForPackage(gameProcessId, GAME_A_PACKAGE); 454 455 mFakeGameService.requestCreateGameSession(10); 456 457 FakeGameSession gameSession10 = new FakeGameSession(); 458 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 459 mFakeGameSessionService.removePendingFutureForTaskId(10) 460 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 461 assertThat(gameSession10.mIsDestroyed).isFalse(); 462 463 // Death of the sole game process destroys the game session. 464 dispatchProcessDied(gameProcessId); 465 assertThat(gameSession10.mIsDestroyed).isTrue(); 466 } 467 468 @Test gameProcessStopped_soleProcess_destroysMultipleGameSessionsForSamePackage()469 public void gameProcessStopped_soleProcess_destroysMultipleGameSessionsForSamePackage() 470 throws Exception { 471 int gameProcessId = 1000; 472 473 mGameServiceProviderInstance.start(); 474 475 // Multiple tasks exist for the same package. 476 startTask(10, GAME_A_MAIN_ACTIVITY); 477 startTask(11, GAME_A_MAIN_ACTIVITY); 478 startProcessForPackage(gameProcessId, GAME_A_PACKAGE); 479 480 mFakeGameService.requestCreateGameSession(10); 481 mFakeGameService.requestCreateGameSession(11); 482 483 FakeGameSession gameSession10 = new FakeGameSession(); 484 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 485 mFakeGameSessionService.removePendingFutureForTaskId(10) 486 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 487 FakeGameSession gameSession11 = new FakeGameSession(); 488 SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class); 489 mFakeGameSessionService.removePendingFutureForTaskId(11) 490 .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11)); 491 492 assertThat(gameSession10.mIsDestroyed).isFalse(); 493 assertThat(gameSession11.mIsDestroyed).isFalse(); 494 495 // Death of the sole game process destroys both game sessions. 496 dispatchProcessDied(gameProcessId); 497 assertThat(gameSession10.mIsDestroyed).isTrue(); 498 assertThat(gameSession11.mIsDestroyed).isTrue(); 499 } 500 501 @Test gameProcessStopped_multipleProcesses_gameSessionDestroyedWhenAllDead()502 public void gameProcessStopped_multipleProcesses_gameSessionDestroyedWhenAllDead() 503 throws Exception { 504 int firstGameProcessId = 1000; 505 int secondGameProcessId = 1001; 506 507 mGameServiceProviderInstance.start(); 508 509 startTask(10, GAME_A_MAIN_ACTIVITY); 510 startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE); 511 startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE); 512 513 mFakeGameService.requestCreateGameSession(10); 514 515 FakeGameSession gameSession10 = new FakeGameSession(); 516 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 517 mFakeGameSessionService.removePendingFutureForTaskId(10) 518 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 519 assertThat(gameSession10.mIsDestroyed).isFalse(); 520 521 // Death of the first process (with the second one still alive) does not destroy the game 522 // session. 523 dispatchProcessDied(firstGameProcessId); 524 assertThat(gameSession10.mIsDestroyed).isFalse(); 525 526 // Death of the second process does destroy the game session. 527 dispatchProcessDied(secondGameProcessId); 528 assertThat(gameSession10.mIsDestroyed).isTrue(); 529 } 530 531 @Test gameProcessCreatedAfterInitialProcessDead_newGameSessionCreated()532 public void gameProcessCreatedAfterInitialProcessDead_newGameSessionCreated() throws Exception { 533 int firstGameProcessId = 1000; 534 int secondGameProcessId = 1000; 535 536 mGameServiceProviderInstance.start(); 537 538 startTask(10, GAME_A_MAIN_ACTIVITY); 539 startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE); 540 541 mFakeGameService.requestCreateGameSession(10); 542 543 FakeGameSession gameSession10 = new FakeGameSession(); 544 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 545 mFakeGameSessionService.removePendingFutureForTaskId(10) 546 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 547 assertThat(gameSession10.mIsDestroyed).isFalse(); 548 549 // After the first game process dies, the game session should be destroyed. 550 dispatchProcessDied(firstGameProcessId); 551 assertThat(gameSession10.mIsDestroyed).isTrue(); 552 553 // However, when a new process for the game starts, a new game session should be created. 554 startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE); 555 // Verify that a new pending game session is created for the game's taskId. 556 assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(10)); 557 } 558 559 @Test gameProcessCreatedAfterInitialProcessDead_multipleGameSessionsCreatedSamePackage()560 public void gameProcessCreatedAfterInitialProcessDead_multipleGameSessionsCreatedSamePackage() 561 throws Exception { 562 int firstGameProcessId = 1000; 563 int secondGameProcessId = 1000; 564 565 mGameServiceProviderInstance.start(); 566 567 // Multiple tasks exist for the same package. 568 startTask(10, GAME_A_MAIN_ACTIVITY); 569 startTask(11, GAME_A_MAIN_ACTIVITY); 570 startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE); 571 572 573 mFakeGameService.requestCreateGameSession(10); 574 mFakeGameService.requestCreateGameSession(11); 575 576 FakeGameSession gameSession10 = new FakeGameSession(); 577 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 578 mFakeGameSessionService.removePendingFutureForTaskId(10) 579 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 580 FakeGameSession gameSession11 = new FakeGameSession(); 581 SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class); 582 mFakeGameSessionService.removePendingFutureForTaskId(11) 583 .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11)); 584 585 assertThat(gameSession10.mIsDestroyed).isFalse(); 586 assertThat(gameSession11.mIsDestroyed).isFalse(); 587 588 // After the first game process dies, both game sessions for the package should be 589 // destroyed. 590 dispatchProcessDied(firstGameProcessId); 591 assertThat(gameSession10.mIsDestroyed).isTrue(); 592 assertThat(gameSession11.mIsDestroyed).isTrue(); 593 594 // However, when a new process for the game starts, new game sessions for the same 595 // package should be created. 596 startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE); 597 // Verify that new pending game sessions were created for each of the game's taskIds. 598 assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(10)); 599 assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(11)); 600 } 601 602 @Test gameProcessStarted_gameSessionNotRequested_doesNothing()603 public void gameProcessStarted_gameSessionNotRequested_doesNothing() throws Exception { 604 int gameProcessId = 1000; 605 606 mGameServiceProviderInstance.start(); 607 608 // A game task and process are started, but requestCreateGameSession is never called. 609 startTask(10, GAME_A_MAIN_ACTIVITY); 610 startProcessForPackage(gameProcessId, GAME_A_PACKAGE); 611 612 613 // No game session should be created. 614 assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).isEmpty(); 615 } 616 617 @Test processActivityAndDeath_notForGame_gameSessionUnaffected()618 public void processActivityAndDeath_notForGame_gameSessionUnaffected() throws Exception { 619 mGameServiceProviderInstance.start(); 620 621 startTask(10, GAME_A_MAIN_ACTIVITY); 622 623 mFakeGameService.requestCreateGameSession(10); 624 625 FakeGameSession gameSession10 = new FakeGameSession(); 626 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 627 mFakeGameSessionService.removePendingFutureForTaskId(10) 628 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 629 630 // Process activity for a process without a known package is ignored. 631 startProcessForPackage(1000, /*packageName=*/ null); 632 dispatchProcessActivity(1000); 633 dispatchProcessDied(1000); 634 635 // Process activity for a process with a different package is ignored 636 startProcessForPackage(1001, GAME_B_PACKAGE); 637 dispatchProcessActivity(1001); 638 dispatchProcessDied(1001); 639 640 // Death of a process for which there was no activity is ignored 641 dispatchProcessDied(1002); 642 643 // Despite all the process activity and death, the game session is not destroyed. 644 assertThat(gameSession10.mIsDestroyed).isFalse(); 645 } 646 647 @Test taskSystemBarsListenerChanged_noAssociatedGameSession_doesNothing()648 public void taskSystemBarsListenerChanged_noAssociatedGameSession_doesNothing() { 649 mGameServiceProviderInstance.start(); 650 651 dispatchTaskSystemBarsEvent(taskSystemBarsListener -> { 652 taskSystemBarsListener.onTransientSystemBarsVisibilityChanged( 653 10, 654 /* areVisible= */ false, 655 /* wereRevealedFromSwipeOnSystemBar= */ false); 656 }); 657 } 658 659 @Test systemBarsTransientShownDueToGesture_hasGameSession_propagatesToGameSession()660 public void systemBarsTransientShownDueToGesture_hasGameSession_propagatesToGameSession() { 661 mGameServiceProviderInstance.start(); 662 startTask(10, GAME_A_MAIN_ACTIVITY); 663 mFakeGameService.requestCreateGameSession(10); 664 665 FakeGameSession gameSession10 = new FakeGameSession(); 666 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 667 mFakeGameSessionService.removePendingFutureForTaskId(10) 668 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 669 670 dispatchTaskSystemBarsEvent(taskSystemBarsListener -> { 671 taskSystemBarsListener.onTransientSystemBarsVisibilityChanged( 672 10, 673 /* areVisible= */ true, 674 /* wereRevealedFromSwipeOnSystemBar= */ true); 675 }); 676 677 assertThat(gameSession10.mAreTransientSystemBarsVisibleFromRevealGesture).isTrue(); 678 } 679 680 @Test systemBarsTransientShownButNotGesture_hasGameSession_notPropagatedToGameSession()681 public void systemBarsTransientShownButNotGesture_hasGameSession_notPropagatedToGameSession() { 682 mGameServiceProviderInstance.start(); 683 startTask(10, GAME_A_MAIN_ACTIVITY); 684 mFakeGameService.requestCreateGameSession(10); 685 686 FakeGameSession gameSession10 = new FakeGameSession(); 687 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 688 mFakeGameSessionService.removePendingFutureForTaskId(10) 689 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 690 691 dispatchTaskSystemBarsEvent(taskSystemBarsListener -> { 692 taskSystemBarsListener.onTransientSystemBarsVisibilityChanged( 693 10, 694 /* areVisible= */ true, 695 /* wereRevealedFromSwipeOnSystemBar= */ false); 696 }); 697 698 assertThat(gameSession10.mAreTransientSystemBarsVisibleFromRevealGesture).isFalse(); 699 } 700 701 @Test gameTaskFocused_propagatedToGameSession()702 public void gameTaskFocused_propagatedToGameSession() throws Exception { 703 mGameServiceProviderInstance.start(); 704 startTask(10, GAME_A_MAIN_ACTIVITY); 705 mFakeGameService.requestCreateGameSession(10); 706 707 FakeGameSession gameSession10 = new FakeGameSession(); 708 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 709 mFakeGameSessionService.removePendingFutureForTaskId(10) 710 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 711 712 assertThat(gameSession10.mIsFocused).isFalse(); 713 714 dispatchTaskFocused(10, /*focused=*/ true); 715 assertThat(gameSession10.mIsFocused).isTrue(); 716 717 dispatchTaskFocused(10, /*focused=*/ false); 718 assertThat(gameSession10.mIsFocused).isFalse(); 719 } 720 721 @Test gameTaskAlreadyFocusedWhenGameSessionCreated_propagatedToGameSession()722 public void gameTaskAlreadyFocusedWhenGameSessionCreated_propagatedToGameSession() 723 throws Exception { 724 ActivityTaskManager.RootTaskInfo gameATaskInfo = new ActivityTaskManager.RootTaskInfo(); 725 gameATaskInfo.taskId = 10; 726 when(mMockActivityTaskManager.getFocusedRootTaskInfo()).thenReturn(gameATaskInfo); 727 728 mGameServiceProviderInstance.start(); 729 startTask(10, GAME_A_MAIN_ACTIVITY); 730 mFakeGameService.requestCreateGameSession(10); 731 732 FakeGameSession gameSession10 = new FakeGameSession(); 733 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 734 mFakeGameSessionService.removePendingFutureForTaskId(10) 735 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 736 737 assertThat(gameSession10.mIsFocused).isTrue(); 738 } 739 740 @Test gameTaskRemoved_whileAwaitingGameSessionAttached_destroysGameSession()741 public void gameTaskRemoved_whileAwaitingGameSessionAttached_destroysGameSession() 742 throws Exception { 743 mGameServiceProviderInstance.start(); 744 745 startTask(10, GAME_A_MAIN_ACTIVITY); 746 mFakeGameService.requestCreateGameSession(10); 747 748 dispatchTaskRemoved(10); 749 750 FakeGameSession gameSession10 = new FakeGameSession(); 751 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 752 mFakeGameSessionService.removePendingFutureForTaskId(10) 753 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 754 755 assertThat(gameSession10.mIsDestroyed).isTrue(); 756 } 757 758 @Test gameTaskRemoved_whileGameSessionAttached_destroysGameSession()759 public void gameTaskRemoved_whileGameSessionAttached_destroysGameSession() throws Exception { 760 mGameServiceProviderInstance.start(); 761 762 startTask(10, GAME_A_MAIN_ACTIVITY); 763 mFakeGameService.requestCreateGameSession(10); 764 765 FakeGameSession gameSession10 = new FakeGameSession(); 766 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 767 mFakeGameSessionService.removePendingFutureForTaskId(10) 768 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 769 770 dispatchTaskRemoved(10); 771 772 assertThat(gameSession10.mIsDestroyed).isTrue(); 773 } 774 775 @Test gameTaskFocusedWithCreateAfterRemoved_gameSessionRecreated()776 public void gameTaskFocusedWithCreateAfterRemoved_gameSessionRecreated() throws Exception { 777 mGameServiceProviderInstance.start(); 778 779 startTask(10, GAME_A_MAIN_ACTIVITY); 780 mFakeGameService.requestCreateGameSession(10); 781 782 FakeGameSession gameSession10 = new FakeGameSession(); 783 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 784 mFakeGameSessionService.removePendingFutureForTaskId(10) 785 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 786 787 stopTask(10); 788 789 assertThat(gameSession10.mIsDestroyed).isTrue(); 790 791 // If the game task is restored via the Recents UI, the task will be running again but 792 // we would not expect any call to TaskStackListener#onTaskCreated. 793 addRunningTaskInfo(10, GAME_A_MAIN_ACTIVITY); 794 795 // We now receive a task focused event for the task. This will occur if the game task is 796 // restored via the Recents UI. 797 dispatchTaskFocused(10, /*focused=*/ true); 798 mFakeGameService.requestCreateGameSession(10); 799 800 // Verify that a new pending game session is created for the game's taskId. 801 assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(10)); 802 } 803 804 @Test gameTaskRemoved_removesTaskOverlay()805 public void gameTaskRemoved_removesTaskOverlay() throws Exception { 806 mGameServiceProviderInstance.start(); 807 808 startTask(10, GAME_A_MAIN_ACTIVITY); 809 mFakeGameService.requestCreateGameSession(10); 810 811 FakeGameSession gameSession10 = new FakeGameSession(); 812 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 813 mFakeGameSessionService.removePendingFutureForTaskId(10) 814 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 815 816 stopTask(10); 817 818 verify(mMockWindowManagerInternal).addTrustedTaskOverlay(eq(10), eq(mockSurfacePackage10)); 819 verify(mMockWindowManagerInternal).removeTrustedTaskOverlay(eq(10), 820 eq(mockSurfacePackage10)); 821 } 822 823 @Test gameTaskStartedAndSessionRequested_multipleTimes_createsMultipleGameSessions()824 public void gameTaskStartedAndSessionRequested_multipleTimes_createsMultipleGameSessions() 825 throws Exception { 826 mGameServiceProviderInstance.start(); 827 828 startTask(10, GAME_A_MAIN_ACTIVITY); 829 mFakeGameService.requestCreateGameSession(10); 830 831 FakeGameSession gameSession10 = new FakeGameSession(); 832 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 833 mFakeGameSessionService.removePendingFutureForTaskId(10) 834 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 835 836 startTask(11, GAME_A_MAIN_ACTIVITY); 837 mFakeGameService.requestCreateGameSession(11); 838 839 FakeGameSession gameSession11 = new FakeGameSession(); 840 SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class); 841 mFakeGameSessionService.removePendingFutureForTaskId(11) 842 .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11)); 843 844 assertThat(gameSession10.mIsDestroyed).isFalse(); 845 assertThat(gameSession11.mIsDestroyed).isFalse(); 846 } 847 848 @Test gameTaskStartedTwice_sessionRequestedSecondTimeOnly_createsOneGameSession()849 public void gameTaskStartedTwice_sessionRequestedSecondTimeOnly_createsOneGameSession() 850 throws Exception { 851 mGameServiceProviderInstance.start(); 852 853 startTask(10, GAME_A_MAIN_ACTIVITY); 854 startTask(11, GAME_A_MAIN_ACTIVITY); 855 856 mFakeGameService.requestCreateGameSession(10); 857 858 FakeGameSession gameSession10 = new FakeGameSession(); 859 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 860 mFakeGameSessionService.removePendingFutureForTaskId(10) 861 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 862 863 assertThat(gameSession10.mIsDestroyed).isFalse(); 864 assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).hasSize(1); 865 } 866 867 @Test gameTaskRemoved_multipleSessions_destroysOnlyThatGameSession()868 public void gameTaskRemoved_multipleSessions_destroysOnlyThatGameSession() 869 throws Exception { 870 mGameServiceProviderInstance.start(); 871 872 startTask(10, GAME_A_MAIN_ACTIVITY); 873 mFakeGameService.requestCreateGameSession(10); 874 875 FakeGameSession gameSession10 = new FakeGameSession(); 876 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 877 mFakeGameSessionService.removePendingFutureForTaskId(10) 878 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 879 880 startTask(11, GAME_A_MAIN_ACTIVITY); 881 mFakeGameService.requestCreateGameSession(11); 882 883 FakeGameSession gameSession11 = new FakeGameSession(); 884 SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class); 885 mFakeGameSessionService.removePendingFutureForTaskId(11) 886 .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11)); 887 888 dispatchTaskRemoved(10); 889 890 assertThat(gameSession10.mIsDestroyed).isTrue(); 891 assertThat(gameSession11.mIsDestroyed).isFalse(); 892 assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isTrue(); 893 } 894 895 @Test allGameTasksRemoved_destroysAllGameSessionsAndGameSessionServiceIsDisconnected()896 public void allGameTasksRemoved_destroysAllGameSessionsAndGameSessionServiceIsDisconnected() { 897 mGameServiceProviderInstance.start(); 898 899 startTask(10, GAME_A_MAIN_ACTIVITY); 900 mFakeGameService.requestCreateGameSession(10); 901 902 FakeGameSession gameSession10 = new FakeGameSession(); 903 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 904 mFakeGameSessionService.removePendingFutureForTaskId(10) 905 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 906 907 startTask(11, GAME_A_MAIN_ACTIVITY); 908 mFakeGameService.requestCreateGameSession(11); 909 910 FakeGameSession gameSession11 = new FakeGameSession(); 911 SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class); 912 mFakeGameSessionService.removePendingFutureForTaskId(11) 913 .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11)); 914 915 dispatchTaskRemoved(10); 916 dispatchTaskRemoved(11); 917 918 assertThat(gameSession10.mIsDestroyed).isTrue(); 919 assertThat(gameSession11.mIsDestroyed).isTrue(); 920 assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isFalse(); 921 } 922 923 @Test createSessionRequested_afterAllPreviousSessionsDestroyed_createsSession()924 public void createSessionRequested_afterAllPreviousSessionsDestroyed_createsSession() 925 throws Exception { 926 mGameServiceProviderInstance.start(); 927 928 startTask(10, GAME_A_MAIN_ACTIVITY); 929 mFakeGameService.requestCreateGameSession(10); 930 931 FakeGameSession gameSession10 = new FakeGameSession(); 932 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 933 mFakeGameSessionService.removePendingFutureForTaskId(10) 934 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 935 936 startTask(11, GAME_A_MAIN_ACTIVITY); 937 mFakeGameService.requestCreateGameSession(11); 938 939 FakeGameSession gameSession11 = new FakeGameSession(); 940 SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class); 941 mFakeGameSessionService.removePendingFutureForTaskId(11) 942 .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11)); 943 944 dispatchTaskRemoved(10); 945 dispatchTaskRemoved(11); 946 947 startTask(12, GAME_A_MAIN_ACTIVITY); 948 mFakeGameService.requestCreateGameSession(12); 949 950 FakeGameSession gameSession12 = new FakeGameSession(); 951 SurfacePackage mockSurfacePackage12 = Mockito.mock(SurfacePackage.class); 952 mFakeGameSessionService.removePendingFutureForTaskId(12) 953 .complete(new CreateGameSessionResult(gameSession12, mockSurfacePackage12)); 954 955 assertThat(gameSession10.mIsDestroyed).isTrue(); 956 assertThat(gameSession11.mIsDestroyed).isTrue(); 957 assertThat(gameSession12.mIsDestroyed).isFalse(); 958 assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isTrue(); 959 } 960 961 @Test gameSessionServiceDies_severalActiveGameSessions_destroysGameSessions()962 public void gameSessionServiceDies_severalActiveGameSessions_destroysGameSessions() { 963 mGameServiceProviderInstance.start(); 964 965 startTask(10, GAME_A_MAIN_ACTIVITY); 966 mFakeGameService.requestCreateGameSession(10); 967 968 FakeGameSession gameSession10 = new FakeGameSession(); 969 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 970 mFakeGameSessionService.removePendingFutureForTaskId(10) 971 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 972 973 startTask(11, GAME_A_MAIN_ACTIVITY); 974 mFakeGameService.requestCreateGameSession(11); 975 976 FakeGameSession gameSession11 = new FakeGameSession(); 977 SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class); 978 mFakeGameSessionService.removePendingFutureForTaskId(11) 979 .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11)); 980 981 mFakeGameSessionServiceConnector.killServiceProcess(); 982 983 assertThat(gameSession10.mIsDestroyed).isTrue(); 984 assertThat(gameSession11.mIsDestroyed).isTrue(); 985 assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue(); 986 assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isFalse(); 987 } 988 989 @Test stop_severalActiveGameSessions_destroysGameSessionsAndUnbinds()990 public void stop_severalActiveGameSessions_destroysGameSessionsAndUnbinds() throws Exception { 991 mGameServiceProviderInstance.start(); 992 993 startTask(10, GAME_A_MAIN_ACTIVITY); 994 mFakeGameService.requestCreateGameSession(10); 995 996 FakeGameSession gameSession10 = new FakeGameSession(); 997 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 998 mFakeGameSessionService.removePendingFutureForTaskId(10) 999 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 1000 1001 startTask(11, GAME_A_MAIN_ACTIVITY); 1002 mFakeGameService.requestCreateGameSession(11); 1003 1004 FakeGameSession gameSession11 = new FakeGameSession(); 1005 SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class); 1006 mFakeGameSessionService.removePendingFutureForTaskId(11) 1007 .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11)); 1008 1009 mGameServiceProviderInstance.stop(); 1010 1011 assertThat(gameSession10.mIsDestroyed).isTrue(); 1012 assertThat(gameSession11.mIsDestroyed).isTrue(); 1013 assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse(); 1014 assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isFalse(); 1015 } 1016 1017 @Test takeScreenshot_failureNoBitmapCaptured()1018 public void takeScreenshot_failureNoBitmapCaptured() throws Exception { 1019 mGameServiceProviderInstance.start(); 1020 startTask(10, GAME_A_MAIN_ACTIVITY); 1021 mFakeGameService.requestCreateGameSession(10); 1022 1023 FakeGameSession gameSession10 = new FakeGameSession(); 1024 SurfacePackage mockOverlaySurfacePackage = Mockito.mock(SurfacePackage.class); 1025 mFakeGameSessionService.removePendingFutureForTaskId(10) 1026 .complete(new CreateGameSessionResult(gameSession10, mockOverlaySurfacePackage)); 1027 1028 IGameSessionController gameSessionController = getOnlyElement( 1029 mFakeGameSessionService.getCapturedCreateInvocations()).mGameSessionController; 1030 AndroidFuture<GameScreenshotResult> resultFuture = new AndroidFuture<>(); 1031 gameSessionController.takeScreenshot(10, resultFuture); 1032 1033 GameScreenshotResult result = resultFuture.get(); 1034 assertEquals(GameScreenshotResult.GAME_SCREENSHOT_ERROR_INTERNAL_ERROR, 1035 result.getStatus()); 1036 1037 verify(mMockWindowManagerService).captureTaskBitmap(eq(10), any()); 1038 } 1039 1040 @Test takeScreenshot_success()1041 public void takeScreenshot_success() throws Exception { 1042 SurfaceControl mockOverlaySurfaceControl = Mockito.mock(SurfaceControl.class); 1043 SurfaceControl[] excludeLayers = new SurfaceControl[1]; 1044 excludeLayers[0] = mockOverlaySurfaceControl; 1045 int taskId = 10; 1046 when(mMockWindowManagerService.captureTaskBitmap(eq(10), any())).thenReturn(TEST_BITMAP); 1047 doAnswer(invocation -> { 1048 Consumer<Uri> consumer = invocation.getArgument(invocation.getArguments().length - 1); 1049 consumer.accept(Uri.parse("a/b.png")); 1050 return null; 1051 }).when(mMockScreenshotHelper).takeScreenshot(any(), any(), any()); 1052 mGameServiceProviderInstance.start(); 1053 startTask(taskId, GAME_A_MAIN_ACTIVITY); 1054 mFakeGameService.requestCreateGameSession(taskId); 1055 1056 FakeGameSession gameSession10 = new FakeGameSession(); 1057 SurfacePackage mockOverlaySurfacePackage = Mockito.mock(SurfacePackage.class); 1058 when(mockOverlaySurfacePackage.getSurfaceControl()).thenReturn(mockOverlaySurfaceControl); 1059 mFakeGameSessionService.removePendingFutureForTaskId(taskId) 1060 .complete(new CreateGameSessionResult(gameSession10, mockOverlaySurfacePackage)); 1061 1062 IGameSessionController gameSessionController = getOnlyElement( 1063 mFakeGameSessionService.getCapturedCreateInvocations()).mGameSessionController; 1064 AndroidFuture<GameScreenshotResult> resultFuture = new AndroidFuture<>(); 1065 gameSessionController.takeScreenshot(taskId, resultFuture); 1066 1067 GameScreenshotResult result = resultFuture.get(); 1068 assertEquals(GameScreenshotResult.GAME_SCREENSHOT_SUCCESS, result.getStatus()); 1069 } 1070 1071 @Test restartGame_taskIdAssociatedWithGame_restartsTargetGame()1072 public void restartGame_taskIdAssociatedWithGame_restartsTargetGame() throws Exception { 1073 Intent launchIntent = new Intent("com.test.ACTION_LAUNCH_GAME_PACKAGE") 1074 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1075 when(mMockPackageManager.getLaunchIntentForPackage(GAME_A_PACKAGE)) 1076 .thenReturn(launchIntent); 1077 1078 mGameServiceProviderInstance.start(); 1079 1080 startTask(10, GAME_A_MAIN_ACTIVITY); 1081 mFakeGameService.requestCreateGameSession(10); 1082 1083 FakeGameSession gameSession10 = new FakeGameSession(); 1084 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 1085 mFakeGameSessionService.removePendingFutureForTaskId(10) 1086 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 1087 1088 startTask(11, GAME_B_MAIN_ACTIVITY); 1089 mFakeGameService.requestCreateGameSession(11); 1090 1091 FakeGameSession gameSession11 = new FakeGameSession(); 1092 SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class); 1093 mFakeGameSessionService.removePendingFutureForTaskId(11) 1094 .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11)); 1095 1096 mFakeGameSessionService.getCapturedCreateInvocations().get(0) 1097 .mGameSessionController.restartGame(10); 1098 1099 verify(mActivityTaskManagerInternal).restartTaskActivityProcessIfVisible( 1100 10, 1101 GAME_A_PACKAGE); 1102 } 1103 1104 @Test restartGame_taskIdNotAssociatedWithGame_noOp()1105 public void restartGame_taskIdNotAssociatedWithGame_noOp() throws Exception { 1106 mGameServiceProviderInstance.start(); 1107 1108 startTask(10, GAME_A_MAIN_ACTIVITY); 1109 mFakeGameService.requestCreateGameSession(10); 1110 1111 FakeGameSession gameSession10 = new FakeGameSession(); 1112 SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class); 1113 mFakeGameSessionService.removePendingFutureForTaskId(10) 1114 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10)); 1115 1116 getOnlyElement( 1117 mFakeGameSessionService.getCapturedCreateInvocations()) 1118 .mGameSessionController.restartGame(11); 1119 1120 verify(mMockActivityManager).registerProcessObserver(any()); 1121 verifyNoMoreInteractions(mMockActivityManager); 1122 verify(mActivityTaskManagerInternal, never()) 1123 .restartTaskActivityProcessIfVisible(anyInt(), anyString()); 1124 } 1125 startTask(int taskId, ComponentName componentName)1126 private void startTask(int taskId, ComponentName componentName) { 1127 addRunningTaskInfo(taskId, componentName); 1128 1129 dispatchTaskCreated(taskId, componentName); 1130 } 1131 addRunningTaskInfo(int taskId, ComponentName componentName)1132 private void addRunningTaskInfo(int taskId, ComponentName componentName) { 1133 RunningTaskInfo runningTaskInfo = new RunningTaskInfo(); 1134 runningTaskInfo.taskId = taskId; 1135 runningTaskInfo.baseActivity = componentName; 1136 runningTaskInfo.displayId = 1; 1137 runningTaskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 0, 500, 800)); 1138 mRunningTaskInfos.add(runningTaskInfo); 1139 } 1140 stopTask(int taskId)1141 private void stopTask(int taskId) { 1142 mRunningTaskInfos.removeIf(runningTaskInfo -> runningTaskInfo.taskId == taskId); 1143 dispatchTaskRemoved(taskId); 1144 } 1145 dispatchTaskRemoved(int taskId)1146 private void dispatchTaskRemoved(int taskId) { 1147 dispatchTaskChangeEvent(taskStackListener -> { 1148 taskStackListener.onTaskRemoved(taskId); 1149 }); 1150 } 1151 dispatchTaskCreated(int taskId, @Nullable ComponentName componentName)1152 private void dispatchTaskCreated(int taskId, @Nullable ComponentName componentName) { 1153 dispatchTaskChangeEvent(taskStackListener -> { 1154 taskStackListener.onTaskCreated(taskId, componentName); 1155 }); 1156 } 1157 dispatchTaskFocused(int taskId, boolean focused)1158 private void dispatchTaskFocused(int taskId, boolean focused) { 1159 dispatchTaskChangeEvent(taskStackListener -> { 1160 taskStackListener.onTaskFocusChanged(taskId, focused); 1161 }); 1162 } 1163 dispatchTaskChangeEvent( ThrowingConsumer<ITaskStackListener> taskStackListenerConsumer)1164 private void dispatchTaskChangeEvent( 1165 ThrowingConsumer<ITaskStackListener> taskStackListenerConsumer) { 1166 for (ITaskStackListener taskStackListener : mTaskStackListeners) { 1167 taskStackListenerConsumer.accept(taskStackListener); 1168 } 1169 } 1170 startProcessForPackage(int processId, @Nullable String packageName)1171 private void startProcessForPackage(int processId, @Nullable String packageName) { 1172 if (packageName != null) { 1173 when(mMockActivityManagerInternal.getPackageNameByPid(processId)).thenReturn( 1174 packageName); 1175 } 1176 1177 dispatchProcessActivity(processId); 1178 } 1179 dispatchProcessActivity(int processId)1180 private void dispatchProcessActivity(int processId) { 1181 dispatchProcessChangedEvent(processObserver -> { 1182 // Neither uid nor foregroundActivities are used by the implementation being tested. 1183 processObserver.onForegroundActivitiesChanged(processId, /*uid=*/ 1184 0, /*foregroundActivities=*/ false); 1185 }); 1186 } 1187 dispatchProcessDied(int processId)1188 private void dispatchProcessDied(int processId) { 1189 dispatchProcessChangedEvent(processObserver -> { 1190 // The uid param is not used by the implementation being tested. 1191 processObserver.onProcessDied(processId, /*uid=*/ 0); 1192 }); 1193 } 1194 dispatchProcessChangedEvent( ThrowingConsumer<IProcessObserver> processObserverConsumer)1195 private void dispatchProcessChangedEvent( 1196 ThrowingConsumer<IProcessObserver> processObserverConsumer) { 1197 for (IProcessObserver processObserver : mProcessObservers) { 1198 processObserverConsumer.accept(processObserver); 1199 } 1200 } 1201 dispatchTaskSystemBarsEvent( ThrowingConsumer<TaskSystemBarsListener> taskSystemBarsListenerConsumer)1202 private void dispatchTaskSystemBarsEvent( 1203 ThrowingConsumer<TaskSystemBarsListener> taskSystemBarsListenerConsumer) { 1204 for (TaskSystemBarsListener listener : mTaskSystemBarsListeners) { 1205 taskSystemBarsListenerConsumer.accept(listener); 1206 } 1207 } 1208 1209 static final class FakeGameService extends IGameService.Stub { 1210 private IGameServiceController mGameServiceController; 1211 1212 public enum GameServiceState { 1213 DISCONNECTED, 1214 CONNECTED, 1215 } 1216 1217 private ArrayList<GameStartedEvent> mGameStartedEvents = new ArrayList<>(); 1218 private int mConnectedCount = 0; 1219 private GameServiceState mGameServiceState = GameServiceState.DISCONNECTED; 1220 getState()1221 public GameServiceState getState() { 1222 return mGameServiceState; 1223 } 1224 getConnectedCount()1225 public int getConnectedCount() { 1226 return mConnectedCount; 1227 } 1228 getGameStartedEvents()1229 public ArrayList<GameStartedEvent> getGameStartedEvents() { 1230 return mGameStartedEvents; 1231 } 1232 1233 @Override connected(IGameServiceController gameServiceController)1234 public void connected(IGameServiceController gameServiceController) { 1235 Preconditions.checkState(mGameServiceState == GameServiceState.DISCONNECTED); 1236 1237 mGameServiceState = GameServiceState.CONNECTED; 1238 mConnectedCount += 1; 1239 mGameServiceController = gameServiceController; 1240 } 1241 1242 @Override disconnected()1243 public void disconnected() { 1244 Preconditions.checkState(mGameServiceState == GameServiceState.CONNECTED); 1245 1246 mGameServiceState = GameServiceState.DISCONNECTED; 1247 mGameServiceController = null; 1248 } 1249 1250 @Override gameStarted(GameStartedEvent gameStartedEvent)1251 public void gameStarted(GameStartedEvent gameStartedEvent) { 1252 Preconditions.checkState(mGameServiceState == GameServiceState.CONNECTED); 1253 1254 mGameStartedEvents.add(gameStartedEvent); 1255 } 1256 requestCreateGameSession(int task)1257 public void requestCreateGameSession(int task) { 1258 Preconditions.checkState(mGameServiceState == GameServiceState.CONNECTED); 1259 1260 try { 1261 mGameServiceController.createGameSession(task); 1262 } catch (RemoteException ex) { 1263 throw new AssertionError(ex); 1264 } 1265 } 1266 } 1267 1268 static final class FakeGameSessionService extends IGameSessionService.Stub { 1269 1270 private final ArrayList<CapturedCreateInvocation> mCapturedCreateInvocations = 1271 new ArrayList<>(); 1272 private final HashMap<Integer, AndroidFuture<CreateGameSessionResult>> 1273 mPendingCreateGameSessionResultFutures = 1274 new HashMap<>(); 1275 1276 public static final class CapturedCreateInvocation { 1277 private final IGameSessionController mGameSessionController; 1278 private final CreateGameSessionRequest mCreateGameSessionRequest; 1279 private final GameSessionViewHostConfiguration mGameSessionViewHostConfiguration; 1280 CapturedCreateInvocation( IGameSessionController gameSessionController, CreateGameSessionRequest createGameSessionRequest, GameSessionViewHostConfiguration gameSessionViewHostConfiguration)1281 CapturedCreateInvocation( 1282 IGameSessionController gameSessionController, 1283 CreateGameSessionRequest createGameSessionRequest, 1284 GameSessionViewHostConfiguration gameSessionViewHostConfiguration) { 1285 mGameSessionController = gameSessionController; 1286 mCreateGameSessionRequest = createGameSessionRequest; 1287 mGameSessionViewHostConfiguration = gameSessionViewHostConfiguration; 1288 } 1289 } 1290 getCapturedCreateInvocations()1291 public ArrayList<CapturedCreateInvocation> getCapturedCreateInvocations() { 1292 return mCapturedCreateInvocations; 1293 } 1294 removePendingFutureForTaskId(int taskId)1295 public AndroidFuture<CreateGameSessionResult> removePendingFutureForTaskId(int taskId) { 1296 return mPendingCreateGameSessionResultFutures.remove(taskId); 1297 } 1298 1299 @Override create( IGameSessionController gameSessionController, CreateGameSessionRequest createGameSessionRequest, GameSessionViewHostConfiguration gameSessionViewHostConfiguration, AndroidFuture createGameSessionResultFuture)1300 public void create( 1301 IGameSessionController gameSessionController, 1302 CreateGameSessionRequest createGameSessionRequest, 1303 GameSessionViewHostConfiguration gameSessionViewHostConfiguration, 1304 AndroidFuture createGameSessionResultFuture) { 1305 1306 mCapturedCreateInvocations.add( 1307 new CapturedCreateInvocation( 1308 gameSessionController, 1309 createGameSessionRequest, 1310 gameSessionViewHostConfiguration)); 1311 1312 Preconditions.checkState(!mPendingCreateGameSessionResultFutures.containsKey( 1313 createGameSessionRequest.getTaskId())); 1314 mPendingCreateGameSessionResultFutures.put( 1315 createGameSessionRequest.getTaskId(), 1316 createGameSessionResultFuture); 1317 } 1318 } 1319 1320 private static class FakeGameSession extends IGameSession.Stub { 1321 boolean mIsDestroyed = false; 1322 boolean mIsFocused = false; 1323 boolean mAreTransientSystemBarsVisibleFromRevealGesture = false; 1324 1325 @Override onDestroyed()1326 public void onDestroyed() { 1327 mIsDestroyed = true; 1328 } 1329 1330 @Override onTaskFocusChanged(boolean focused)1331 public void onTaskFocusChanged(boolean focused) { 1332 mIsFocused = focused; 1333 } 1334 1335 @Override onTransientSystemBarVisibilityFromRevealGestureChanged(boolean areVisible)1336 public void onTransientSystemBarVisibilityFromRevealGestureChanged(boolean areVisible) { 1337 mAreTransientSystemBarsVisibleFromRevealGesture = areVisible; 1338 } 1339 } 1340 1341 private final class MockContext extends ContextWrapper { MockContext(Context base)1342 MockContext(Context base) { 1343 super(base); 1344 } 1345 @Override getPackageManager()1346 public PackageManager getPackageManager() { 1347 return mMockPackageManager; 1348 } 1349 } 1350 } 1351