Merge "If necessary, re-create game session when game task is focused." into tm-dev
This commit is contained in:
@@ -20,9 +20,11 @@ import android.annotation.NonNull;
|
|||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.ActivityManagerInternal;
|
import android.app.ActivityManagerInternal;
|
||||||
import android.app.ActivityTaskManager;
|
import android.app.ActivityTaskManager;
|
||||||
|
import android.app.IActivityTaskManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.service.games.GameService;
|
import android.service.games.GameService;
|
||||||
import android.service.games.GameSessionService;
|
import android.service.games.GameSessionService;
|
||||||
import android.service.games.IGameService;
|
import android.service.games.IGameService;
|
||||||
@@ -47,14 +49,17 @@ final class GameServiceProviderInstanceFactoryImpl implements GameServiceProvide
|
|||||||
@Override
|
@Override
|
||||||
public GameServiceProviderInstance create(
|
public GameServiceProviderInstance create(
|
||||||
@NonNull GameServiceComponentConfiguration configuration) {
|
@NonNull GameServiceComponentConfiguration configuration) {
|
||||||
|
final UserHandle userHandle = configuration.getUserHandle();
|
||||||
|
final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService();
|
||||||
return new GameServiceProviderInstanceImpl(
|
return new GameServiceProviderInstanceImpl(
|
||||||
configuration.getUserHandle(),
|
userHandle,
|
||||||
BackgroundThread.getExecutor(),
|
BackgroundThread.getExecutor(),
|
||||||
mContext,
|
mContext,
|
||||||
new GameClassifierImpl(mContext.getPackageManager()),
|
new GameTaskInfoProvider(userHandle, activityTaskManager,
|
||||||
|
new GameClassifierImpl(mContext.getPackageManager())),
|
||||||
ActivityManager.getService(),
|
ActivityManager.getService(),
|
||||||
LocalServices.getService(ActivityManagerInternal.class),
|
LocalServices.getService(ActivityManagerInternal.class),
|
||||||
ActivityTaskManager.getService(),
|
activityTaskManager,
|
||||||
(WindowManagerService) ServiceManager.getService(Context.WINDOW_SERVICE),
|
(WindowManagerService) ServiceManager.getService(Context.WINDOW_SERVICE),
|
||||||
LocalServices.getService(WindowManagerInternal.class),
|
LocalServices.getService(WindowManagerInternal.class),
|
||||||
new GameServiceConnector(mContext, configuration),
|
new GameServiceConnector(mContext, configuration),
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ import com.android.server.wm.WindowManagerInternal;
|
|||||||
import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
|
import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
|
||||||
import com.android.server.wm.WindowManagerService;
|
import com.android.server.wm.WindowManagerService;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -218,7 +217,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
|||||||
private final UserHandle mUserHandle;
|
private final UserHandle mUserHandle;
|
||||||
private final Executor mBackgroundExecutor;
|
private final Executor mBackgroundExecutor;
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final GameClassifier mGameClassifier;
|
private final GameTaskInfoProvider mGameTaskInfoProvider;
|
||||||
private final IActivityManager mActivityManager;
|
private final IActivityManager mActivityManager;
|
||||||
private final ActivityManagerInternal mActivityManagerInternal;
|
private final ActivityManagerInternal mActivityManagerInternal;
|
||||||
private final IActivityTaskManager mActivityTaskManager;
|
private final IActivityTaskManager mActivityTaskManager;
|
||||||
@@ -244,7 +243,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
|||||||
@NonNull UserHandle userHandle,
|
@NonNull UserHandle userHandle,
|
||||||
@NonNull Executor backgroundExecutor,
|
@NonNull Executor backgroundExecutor,
|
||||||
@NonNull Context context,
|
@NonNull Context context,
|
||||||
@NonNull GameClassifier gameClassifier,
|
@NonNull GameTaskInfoProvider gameTaskInfoProvider,
|
||||||
@NonNull IActivityManager activityManager,
|
@NonNull IActivityManager activityManager,
|
||||||
@NonNull ActivityManagerInternal activityManagerInternal,
|
@NonNull ActivityManagerInternal activityManagerInternal,
|
||||||
@NonNull IActivityTaskManager activityTaskManager,
|
@NonNull IActivityTaskManager activityTaskManager,
|
||||||
@@ -256,7 +255,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
|||||||
mUserHandle = userHandle;
|
mUserHandle = userHandle;
|
||||||
mBackgroundExecutor = backgroundExecutor;
|
mBackgroundExecutor = backgroundExecutor;
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mGameClassifier = gameClassifier;
|
mGameTaskInfoProvider = gameTaskInfoProvider;
|
||||||
mActivityManager = activityManager;
|
mActivityManager = activityManager;
|
||||||
mActivityManagerInternal = activityManagerInternal;
|
mActivityManagerInternal = activityManagerInternal;
|
||||||
mActivityTaskManager = activityTaskManager;
|
mActivityTaskManager = activityTaskManager;
|
||||||
@@ -344,13 +343,14 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onTaskCreated(int taskId, @NonNull ComponentName componentName) {
|
private void onTaskCreated(int taskId, @NonNull ComponentName componentName) {
|
||||||
String packageName = componentName.getPackageName();
|
final GameTaskInfo taskInfo = mGameTaskInfoProvider.get(taskId, componentName);
|
||||||
if (!mGameClassifier.isGame(packageName, mUserHandle)) {
|
|
||||||
|
if (!taskInfo.mIsGameTask) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
gameTaskStartedLocked(taskId, componentName);
|
gameTaskStartedLocked(taskInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +367,17 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
|||||||
}
|
}
|
||||||
|
|
||||||
final GameSessionRecord gameSessionRecord = mGameSessions.get(taskId);
|
final GameSessionRecord gameSessionRecord = mGameSessions.get(taskId);
|
||||||
if (gameSessionRecord == null || gameSessionRecord.getGameSession() == null) {
|
if (gameSessionRecord == null) {
|
||||||
|
if (focused) {
|
||||||
|
// The game session for a game task may have been destroyed when the game task
|
||||||
|
// was put into the background by pressing the back button. If the task is restored
|
||||||
|
// via the Recents UI there will be no TaskStackListener#onCreated call for the
|
||||||
|
// restoration, so this focus event is the first opportunity to re-create the game
|
||||||
|
// session.
|
||||||
|
maybeCreateGameSessionForFocusedTaskLocked(taskId);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (gameSessionRecord.getGameSession() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,30 +389,50 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private void gameTaskStartedLocked(int taskId, @NonNull ComponentName componentName) {
|
private void maybeCreateGameSessionForFocusedTaskLocked(int taskId) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.i(TAG, "gameStartedLocked() id: " + taskId + " component: " + componentName);
|
Slog.d(TAG, "maybeRecreateGameSessionForFocusedTaskLocked() id: " + taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
final GameTaskInfo taskInfo = mGameTaskInfoProvider.get(taskId);
|
||||||
|
if (taskInfo == null) {
|
||||||
|
Slog.w(TAG, "No task info for focused task: " + taskId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!taskInfo.mIsGameTask) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gameTaskStartedLocked(taskInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private void gameTaskStartedLocked(@NonNull GameTaskInfo gameTaskInfo) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.i(TAG, "gameStartedLocked(): " + gameTaskInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mIsRunning) {
|
if (!mIsRunning) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameSessionRecord existingGameSessionRecord = mGameSessions.get(taskId);
|
GameSessionRecord existingGameSessionRecord = mGameSessions.get(gameTaskInfo.mTaskId);
|
||||||
if (existingGameSessionRecord != null) {
|
if (existingGameSessionRecord != null) {
|
||||||
Slog.w(TAG, "Existing game session found for task (id: " + taskId
|
Slog.w(TAG, "Existing game session found for task (id: " + gameTaskInfo.mTaskId
|
||||||
+ ") creation. Ignoring.");
|
+ ") creation. Ignoring.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameSessionRecord gameSessionRecord = GameSessionRecord.awaitingGameSessionRequest(
|
GameSessionRecord gameSessionRecord = GameSessionRecord.awaitingGameSessionRequest(
|
||||||
taskId, componentName);
|
gameTaskInfo.mTaskId, gameTaskInfo.mComponentName);
|
||||||
mGameSessions.put(taskId, gameSessionRecord);
|
mGameSessions.put(gameTaskInfo.mTaskId, gameSessionRecord);
|
||||||
|
|
||||||
AndroidFuture<Void> unusedPostGameStartedFuture = mGameServiceConnector.post(
|
AndroidFuture<Void> unusedPostGameStartedFuture = mGameServiceConnector.post(
|
||||||
gameService -> {
|
gameService -> {
|
||||||
gameService.gameStarted(
|
gameService.gameStarted(
|
||||||
new GameStartedEvent(taskId, componentName.getPackageName()));
|
new GameStartedEvent(gameTaskInfo.mTaskId,
|
||||||
|
gameTaskInfo.mComponentName.getPackageName()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -769,7 +799,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private GameSessionViewHostConfiguration createViewHostConfigurationForTask(int taskId) {
|
private GameSessionViewHostConfiguration createViewHostConfigurationForTask(int taskId) {
|
||||||
RunningTaskInfo runningTaskInfo = getRunningTaskInfoForTask(taskId);
|
RunningTaskInfo runningTaskInfo = mGameTaskInfoProvider.getRunningTaskInfo(taskId);
|
||||||
if (runningTaskInfo == null) {
|
if (runningTaskInfo == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -781,28 +811,6 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
|||||||
bounds.height());
|
bounds.height());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private RunningTaskInfo getRunningTaskInfoForTask(int taskId) {
|
|
||||||
List<RunningTaskInfo> runningTaskInfos;
|
|
||||||
try {
|
|
||||||
runningTaskInfos = mActivityTaskManager.getTasks(
|
|
||||||
/* maxNum= */ Integer.MAX_VALUE,
|
|
||||||
/* filterOnlyVisibleRecents= */ true,
|
|
||||||
/* keepIntentExtra= */ false);
|
|
||||||
} catch (RemoteException ex) {
|
|
||||||
Slog.w(TAG, "Failed to fetch running tasks");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (RunningTaskInfo taskInfo : runningTaskInfos) {
|
|
||||||
if (taskInfo.taskId == taskId) {
|
|
||||||
return taskInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void takeScreenshot(int taskId, @NonNull AndroidFuture callback) {
|
void takeScreenshot(int taskId, @NonNull AndroidFuture callback) {
|
||||||
GameSessionRecord gameSessionRecord;
|
GameSessionRecord gameSessionRecord;
|
||||||
@@ -834,7 +842,8 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
|||||||
} else {
|
} else {
|
||||||
final Bundle bundle = ScreenshotHelper.HardwareBitmapBundler.hardwareBitmapToBundle(
|
final Bundle bundle = ScreenshotHelper.HardwareBitmapBundler.hardwareBitmapToBundle(
|
||||||
bitmap);
|
bitmap);
|
||||||
final RunningTaskInfo runningTaskInfo = getRunningTaskInfoForTask(taskId);
|
final RunningTaskInfo runningTaskInfo =
|
||||||
|
mGameTaskInfoProvider.getRunningTaskInfo(taskId);
|
||||||
if (runningTaskInfo == null) {
|
if (runningTaskInfo == null) {
|
||||||
Slog.w(TAG, "Could not get running task info for id: " + taskId);
|
Slog.w(TAG, "Could not get running task info for id: " + taskId);
|
||||||
callback.complete(GameScreenshotResult.createInternalErrorResult());
|
callback.complete(GameScreenshotResult.createInternalErrorResult());
|
||||||
|
|||||||
66
services/core/java/com/android/server/app/GameTaskInfo.java
Normal file
66
services/core/java/com/android/server/app/GameTaskInfo.java
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.app;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
final class GameTaskInfo {
|
||||||
|
final int mTaskId;
|
||||||
|
final boolean mIsGameTask;
|
||||||
|
final ComponentName mComponentName;
|
||||||
|
|
||||||
|
GameTaskInfo(int taskId, boolean isGameTask, ComponentName componentName) {
|
||||||
|
mTaskId = taskId;
|
||||||
|
mIsGameTask = isGameTask;
|
||||||
|
mComponentName = componentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "GameTaskInfo{"
|
||||||
|
+ "mTaskId="
|
||||||
|
+ mTaskId
|
||||||
|
+ ", mIsGameTask="
|
||||||
|
+ mIsGameTask
|
||||||
|
+ ", mComponentName="
|
||||||
|
+ mComponentName
|
||||||
|
+ '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(o instanceof GameTaskInfo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameTaskInfo that = (GameTaskInfo) o;
|
||||||
|
return mTaskId == that.mTaskId
|
||||||
|
&& mIsGameTask == that.mIsGameTask
|
||||||
|
&& mComponentName.equals(that.mComponentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(mTaskId, mIsGameTask, mComponentName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.app;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
|
import android.app.IActivityTaskManager;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.util.LruCache;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
final class GameTaskInfoProvider {
|
||||||
|
private static final String TAG = "GameTaskInfoProvider";
|
||||||
|
private static final int TASK_INFO_CACHE_MAX_SIZE = 50;
|
||||||
|
|
||||||
|
private final Object mLock = new Object();
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private final LruCache<Integer, GameTaskInfo> mGameTaskInfoCache = new LruCache<>(
|
||||||
|
TASK_INFO_CACHE_MAX_SIZE);
|
||||||
|
|
||||||
|
private final UserHandle mUserHandle;
|
||||||
|
private final IActivityTaskManager mActivityTaskManager;
|
||||||
|
private final GameClassifier mGameClassifier;
|
||||||
|
|
||||||
|
GameTaskInfoProvider(@NonNull UserHandle userHandle,
|
||||||
|
@NonNull IActivityTaskManager activityTaskManager,
|
||||||
|
@NonNull GameClassifier gameClassifier) {
|
||||||
|
mUserHandle = userHandle;
|
||||||
|
mActivityTaskManager = activityTaskManager;
|
||||||
|
mGameClassifier = gameClassifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
GameTaskInfo get(int taskId) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
final GameTaskInfo cachedTaskInfo = mGameTaskInfoCache.get(taskId);
|
||||||
|
if (cachedTaskInfo != null) {
|
||||||
|
return cachedTaskInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final RunningTaskInfo runningTaskInfo = getRunningTaskInfo(taskId);
|
||||||
|
if (runningTaskInfo == null || runningTaskInfo.baseActivity == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateGameInfo(taskId, runningTaskInfo.baseActivity);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameTaskInfo get(int taskId, @NonNull ComponentName componentName) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
final GameTaskInfo cachedTaskInfo = mGameTaskInfoCache.get(taskId);
|
||||||
|
if (cachedTaskInfo != null) {
|
||||||
|
if (cachedTaskInfo.mComponentName.equals(componentName)) {
|
||||||
|
Slog.w(TAG, "Found cached task info for taskId " + taskId
|
||||||
|
+ " but cached component name " + cachedTaskInfo.mComponentName
|
||||||
|
+ " does not match " + componentName);
|
||||||
|
} else {
|
||||||
|
return cachedTaskInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateGameInfo(taskId, componentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
RunningTaskInfo getRunningTaskInfo(int taskId) {
|
||||||
|
List<RunningTaskInfo> runningTaskInfos;
|
||||||
|
try {
|
||||||
|
runningTaskInfos = mActivityTaskManager.getTasks(
|
||||||
|
/* maxNum= */ Integer.MAX_VALUE,
|
||||||
|
/* filterOnlyVisibleRecents= */ false,
|
||||||
|
/* keepIntentExtra= */ false);
|
||||||
|
} catch (RemoteException ex) {
|
||||||
|
Slog.w(TAG, "Failed to fetch running tasks");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (RunningTaskInfo taskInfo : runningTaskInfos) {
|
||||||
|
if (taskInfo.taskId == taskId) {
|
||||||
|
return taskInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GameTaskInfo generateGameInfo(int taskId, @NonNull ComponentName componentName) {
|
||||||
|
final GameTaskInfo gameTaskInfo = new GameTaskInfo(taskId,
|
||||||
|
mGameClassifier.isGame(componentName.getPackageName(), mUserHandle), componentName);
|
||||||
|
|
||||||
|
synchronized (mLock) {
|
||||||
|
mGameTaskInfoCache.put(taskId, gameTaskInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gameTaskInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -216,11 +216,12 @@ public final class GameServiceProviderInstanceImplTest {
|
|||||||
mRunningTaskInfos);
|
mRunningTaskInfos);
|
||||||
|
|
||||||
|
|
||||||
|
final UserHandle userHandle = new UserHandle(USER_ID);
|
||||||
mGameServiceProviderInstance = new GameServiceProviderInstanceImpl(
|
mGameServiceProviderInstance = new GameServiceProviderInstanceImpl(
|
||||||
new UserHandle(USER_ID),
|
userHandle,
|
||||||
ConcurrentUtils.DIRECT_EXECUTOR,
|
ConcurrentUtils.DIRECT_EXECUTOR,
|
||||||
mMockContext,
|
mMockContext,
|
||||||
mFakeGameClassifier,
|
new GameTaskInfoProvider(userHandle, mMockActivityTaskManager, mFakeGameClassifier),
|
||||||
mMockActivityManager,
|
mMockActivityManager,
|
||||||
mMockActivityManagerInternal,
|
mMockActivityManagerInternal,
|
||||||
mMockActivityTaskManager,
|
mMockActivityTaskManager,
|
||||||
@@ -787,6 +788,36 @@ public final class GameServiceProviderInstanceImplTest {
|
|||||||
assertThat(gameSession10.mIsDestroyed).isTrue();
|
assertThat(gameSession10.mIsDestroyed).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void gameTaskFocusedWithCreateAfterRemoved_gameSessionRecreated() throws Exception {
|
||||||
|
mGameServiceProviderInstance.start();
|
||||||
|
|
||||||
|
startTask(10, GAME_A_MAIN_ACTIVITY);
|
||||||
|
mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
|
||||||
|
mFakeGameService.requestCreateGameSession(10);
|
||||||
|
|
||||||
|
FakeGameSession gameSession10 = new FakeGameSession();
|
||||||
|
SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
|
||||||
|
mFakeGameSessionService.removePendingFutureForTaskId(10)
|
||||||
|
.complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
|
||||||
|
|
||||||
|
stopTask(10);
|
||||||
|
|
||||||
|
assertThat(gameSession10.mIsDestroyed).isTrue();
|
||||||
|
|
||||||
|
// If the game task is restored via the Recents UI, the task will be running again but
|
||||||
|
// we would not expect any call to TaskStackListener#onTaskCreated.
|
||||||
|
addRunningTaskInfo(10, GAME_A_MAIN_ACTIVITY);
|
||||||
|
|
||||||
|
// We now receive a task focused event for the task. This will occur if the game task is
|
||||||
|
// restored via the Recents UI.
|
||||||
|
dispatchTaskFocused(10, /*focused=*/ true);
|
||||||
|
mFakeGameService.requestCreateGameSession(10);
|
||||||
|
|
||||||
|
// Verify that a new pending game session is created for the game's taskId.
|
||||||
|
assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(10));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void gameTaskRemoved_removesTaskOverlay() throws Exception {
|
public void gameTaskRemoved_removesTaskOverlay() throws Exception {
|
||||||
mGameServiceProviderInstance.start();
|
mGameServiceProviderInstance.start();
|
||||||
@@ -1144,13 +1175,18 @@ public final class GameServiceProviderInstanceImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void startTask(int taskId, ComponentName componentName) {
|
private void startTask(int taskId, ComponentName componentName) {
|
||||||
|
addRunningTaskInfo(taskId, componentName);
|
||||||
|
|
||||||
|
dispatchTaskCreated(taskId, componentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRunningTaskInfo(int taskId, ComponentName componentName) {
|
||||||
RunningTaskInfo runningTaskInfo = new RunningTaskInfo();
|
RunningTaskInfo runningTaskInfo = new RunningTaskInfo();
|
||||||
runningTaskInfo.taskId = taskId;
|
runningTaskInfo.taskId = taskId;
|
||||||
|
runningTaskInfo.baseActivity = componentName;
|
||||||
runningTaskInfo.displayId = 1;
|
runningTaskInfo.displayId = 1;
|
||||||
runningTaskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 0, 500, 800));
|
runningTaskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 0, 500, 800));
|
||||||
mRunningTaskInfos.add(runningTaskInfo);
|
mRunningTaskInfos.add(runningTaskInfo);
|
||||||
|
|
||||||
dispatchTaskCreated(taskId, componentName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopTask(int taskId) {
|
private void stopTask(int taskId) {
|
||||||
|
|||||||
Reference in New Issue
Block a user