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