Merge "Allow Game Service to trigger the Game Session creation"
This commit is contained in:
@@ -10877,9 +10877,11 @@ package android.service.games {
|
||||
|
||||
public class GameService extends android.app.Service {
|
||||
ctor public GameService();
|
||||
method public final void createGameSession(@IntRange(from=0) int);
|
||||
method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
|
||||
method public void onConnected();
|
||||
method public void onDisconnected();
|
||||
method public void onGameStarted(@NonNull android.service.games.GameStartedEvent);
|
||||
field public static final String ACTION_GAME_SERVICE = "android.service.games.action.GAME_SERVICE";
|
||||
field public static final String SERVICE_META_DATA = "android.game_service";
|
||||
}
|
||||
@@ -10897,6 +10899,15 @@ package android.service.games {
|
||||
field public static final String ACTION_GAME_SESSION_SERVICE = "android.service.games.action.GAME_SESSION_SERVICE";
|
||||
}
|
||||
|
||||
public final class GameStartedEvent implements android.os.Parcelable {
|
||||
ctor public GameStartedEvent(@IntRange(from=0) int, @NonNull String);
|
||||
method public int describeContents();
|
||||
method @NonNull public String getPackageName();
|
||||
method @IntRange(from=0) public int getTaskId();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.service.games.GameStartedEvent> CREATOR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.service.notification {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.service.games;
|
||||
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SystemApi;
|
||||
@@ -38,6 +40,12 @@ import java.util.Objects;
|
||||
* when a game session should begin. It is always kept running by the system.
|
||||
* Because of this it should be kept as lightweight as possible.
|
||||
*
|
||||
* <p> Instead of requiring permissions for sensitive actions (e.g., starting a new game session),
|
||||
* this class is provided with an {@link IGameServiceController} instance which exposes the
|
||||
* sensitive functionality. This controller is provided by the system server when calling the
|
||||
* {@link IGameService#connected(IGameServiceController)} method exposed by this class. The system
|
||||
* server does so only when creating the bound game service.
|
||||
*
|
||||
* <p>Heavyweight operations (such as showing UI) should be implemented in the
|
||||
* associated {@link GameSessionService} when a game session is taking place. Its
|
||||
* implementation should run in a separate process from the {@link GameService}.
|
||||
@@ -79,12 +87,13 @@ public class GameService extends Service {
|
||||
*/
|
||||
public static final String SERVICE_META_DATA = "android.game_service";
|
||||
|
||||
private IGameServiceController mGameServiceController;
|
||||
private IGameManagerService mGameManagerService;
|
||||
private final IGameService mInterface = new IGameService.Stub() {
|
||||
@Override
|
||||
public void connected() {
|
||||
public void connected(IGameServiceController gameServiceController) {
|
||||
Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
|
||||
GameService::doOnConnected, GameService.this));
|
||||
GameService::doOnConnected, GameService.this, gameServiceController));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,6 +101,12 @@ public class GameService extends Service {
|
||||
Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
|
||||
GameService::onDisconnected, GameService.this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gameStarted(GameStartedEvent gameStartedEvent) {
|
||||
Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
|
||||
GameService::onGameStarted, GameService.this, gameStartedEvent));
|
||||
}
|
||||
};
|
||||
|
||||
private final IBinder.DeathRecipient mGameManagerServiceDeathRecipient = () -> {
|
||||
@@ -111,7 +126,7 @@ public class GameService extends Service {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void doOnConnected() {
|
||||
private void doOnConnected(@NonNull IGameServiceController gameServiceController) {
|
||||
mGameManagerService =
|
||||
IGameManagerService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.GAME_SERVICE));
|
||||
@@ -122,6 +137,7 @@ public class GameService extends Service {
|
||||
Log.w(TAG, "Unable to link to death with system service");
|
||||
}
|
||||
|
||||
mGameServiceController = gameServiceController;
|
||||
onConnected();
|
||||
}
|
||||
|
||||
@@ -138,4 +154,34 @@ public class GameService extends Service {
|
||||
* The service should clean up any resources that it holds at this point.
|
||||
*/
|
||||
public void onDisconnected() {}
|
||||
|
||||
/**
|
||||
* Called when a game task is started. It is the responsibility of the service to determine what
|
||||
* action to take (e.g., request that a game session be created).
|
||||
*
|
||||
* @param gameStartedEvent Contains information about the game being started.
|
||||
*/
|
||||
public void onGameStarted(@NonNull GameStartedEvent gameStartedEvent) {}
|
||||
|
||||
/**
|
||||
* Call to create a new game session be created for a game. This method may be called
|
||||
* by a game service following {@link #onGameStarted}, using the task ID provided by the
|
||||
* provided {@link GameStartedEvent} (using {@link GameStartedEvent#getTaskId}).
|
||||
*
|
||||
* If a game session already exists for the game task, this call will be ignored and the
|
||||
* existing session will continue.
|
||||
*
|
||||
* @param taskId The taskId of the game.
|
||||
*/
|
||||
public final void createGameSession(@IntRange(from = 0) int taskId) {
|
||||
if (mGameServiceController == null) {
|
||||
throw new IllegalStateException("Can not call before connected()");
|
||||
}
|
||||
|
||||
try {
|
||||
mGameServiceController.createGameSession(taskId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Request for game session failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
core/java/android/service/games/GameStartedEvent.aidl
Normal file
23
core/java/android/service/games/GameStartedEvent.aidl
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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 android.service.games;
|
||||
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
parcelable GameStartedEvent;
|
||||
119
core/java/android/service/games/GameStartedEvent.java
Normal file
119
core/java/android/service/games/GameStartedEvent.java
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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 android.service.games;
|
||||
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Event object provided when a game task is started.
|
||||
*
|
||||
* This is provided to the Game Service via
|
||||
* {@link GameService#onGameStarted(GameStartedEvent)}. It includes the game's taskId
|
||||
* (see {@link #getTaskId}) that the game's package name (see {@link #getPackageName}).
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class GameStartedEvent implements Parcelable {
|
||||
|
||||
@NonNull
|
||||
public static final Parcelable.Creator<GameStartedEvent> CREATOR =
|
||||
new Parcelable.Creator<GameStartedEvent>() {
|
||||
@Override
|
||||
public GameStartedEvent createFromParcel(Parcel source) {
|
||||
return new GameStartedEvent(
|
||||
source.readInt(),
|
||||
source.readString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameStartedEvent[] newArray(int size) {
|
||||
return new GameStartedEvent[0];
|
||||
}
|
||||
};
|
||||
|
||||
private final int mTaskId;
|
||||
private final String mPackageName;
|
||||
|
||||
public GameStartedEvent(@IntRange(from = 0) int taskId, @NonNull String packageName) {
|
||||
this.mTaskId = taskId;
|
||||
this.mPackageName = packageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mTaskId);
|
||||
dest.writeString(mPackageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unique identifier for the task associated with the game.
|
||||
*/
|
||||
@IntRange(from = 0)
|
||||
public int getTaskId() {
|
||||
return mTaskId;
|
||||
}
|
||||
|
||||
/**
|
||||
* The package name for the game.
|
||||
*/
|
||||
@NonNull
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GameStartedEvent{"
|
||||
+ "mTaskId="
|
||||
+ mTaskId
|
||||
+ ", mPackageName='"
|
||||
+ mPackageName
|
||||
+ "\'}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof GameStartedEvent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GameStartedEvent that = (GameStartedEvent) o;
|
||||
return mTaskId == that.mTaskId
|
||||
&& Objects.equals(mPackageName, that.mPackageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mTaskId, mPackageName);
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,14 @@
|
||||
|
||||
package android.service.games;
|
||||
|
||||
import android.service.games.GameStartedEvent;
|
||||
import android.service.games.IGameServiceController;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IGameService {
|
||||
void connected();
|
||||
void connected(in IGameServiceController gameServiceController);
|
||||
void disconnected();
|
||||
void gameStarted(in GameStartedEvent gameStartedEvent);
|
||||
}
|
||||
|
||||
24
core/java/android/service/games/IGameServiceController.aidl
Normal file
24
core/java/android/service/games/IGameServiceController.aidl
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 android.service.games;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IGameServiceController {
|
||||
void createGameSession(int taskId);
|
||||
}
|
||||
@@ -24,7 +24,9 @@ import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.service.games.CreateGameSessionRequest;
|
||||
import android.service.games.GameStartedEvent;
|
||||
import android.service.games.IGameService;
|
||||
import android.service.games.IGameServiceController;
|
||||
import android.service.games.IGameSession;
|
||||
import android.service.games.IGameSessionService;
|
||||
import android.util.Slog;
|
||||
@@ -61,6 +63,17 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private final IGameServiceController mGameServiceController =
|
||||
new IGameServiceController.Stub() {
|
||||
@Override
|
||||
public void createGameSession(int taskId) {
|
||||
mBackgroundExecutor.execute(() -> {
|
||||
GameServiceProviderInstanceImpl.this.createGameSession(taskId);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final UserHandle mUserHandle;
|
||||
private final Executor mBackgroundExecutor;
|
||||
@@ -114,7 +127,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
||||
// TODO(b/204503192): In cases where the connection to the game service fails retry with
|
||||
// back off mechanism.
|
||||
AndroidFuture<Void> unusedPostConnectedFuture = mGameServiceConnector.post(gameService -> {
|
||||
gameService.connected();
|
||||
gameService.connected(mGameServiceController);
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -168,25 +181,14 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
createGameSessionLocked(taskId, componentName);
|
||||
}
|
||||
}
|
||||
|
||||
private void onTaskRemoved(int taskId) {
|
||||
synchronized (mLock) {
|
||||
boolean isTaskAssociatedWithGameSession = mGameSessions.containsKey(taskId);
|
||||
if (!isTaskAssociatedWithGameSession) {
|
||||
return;
|
||||
}
|
||||
|
||||
destroyGameSessionLocked(taskId);
|
||||
gameTaskStartedLocked(taskId, componentName);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void createGameSessionLocked(int sessionId, @NonNull ComponentName componentName) {
|
||||
private void gameTaskStartedLocked(int sessionId, @NonNull ComponentName componentName) {
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "createGameSession() id: " + sessionId + " component: " + componentName);
|
||||
Slog.i(TAG, "gameStartedLocked() id: " + sessionId + " component: " + componentName);
|
||||
}
|
||||
|
||||
if (!mIsRunning) {
|
||||
@@ -200,10 +202,59 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
||||
return;
|
||||
}
|
||||
|
||||
GameSessionRecord gameSessionRecord = GameSessionRecord.pendingGameSession(sessionId,
|
||||
componentName);
|
||||
GameSessionRecord gameSessionRecord = GameSessionRecord.awaitingGameSessionRequest(
|
||||
sessionId, componentName);
|
||||
mGameSessions.put(sessionId, gameSessionRecord);
|
||||
|
||||
AndroidFuture<Void> unusedPostGameStartedFuture = mGameServiceConnector.post(
|
||||
gameService -> {
|
||||
gameService.gameStarted(
|
||||
new GameStartedEvent(sessionId, componentName.getPackageName()));
|
||||
});
|
||||
}
|
||||
|
||||
private void onTaskRemoved(int taskId) {
|
||||
synchronized (mLock) {
|
||||
boolean isTaskAssociatedWithGameSession = mGameSessions.containsKey(taskId);
|
||||
if (!isTaskAssociatedWithGameSession) {
|
||||
return;
|
||||
}
|
||||
|
||||
destroyGameSessionIfNecessaryLocked(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
private void createGameSession(int taskId) {
|
||||
synchronized (mLock) {
|
||||
createGameSessionLocked(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void createGameSessionLocked(int sessionId) {
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "createGameSessionLocked() id: " + sessionId);
|
||||
}
|
||||
|
||||
if (!mIsRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
GameSessionRecord existingGameSessionRecord = mGameSessions.get(sessionId);
|
||||
if (existingGameSessionRecord == null) {
|
||||
Slog.w(TAG, "No existing game session record found for task (id: " + sessionId
|
||||
+ ") creation. Ignoring.");
|
||||
return;
|
||||
}
|
||||
if (!existingGameSessionRecord.isAwaitingGameSessionRequest()) {
|
||||
Slog.w(TAG, "Existing game session for task (id: " + sessionId
|
||||
+ ") is not awaiting game session request. Ignoring.");
|
||||
return;
|
||||
}
|
||||
mGameSessions.put(sessionId, existingGameSessionRecord.withGameSessionRequested());
|
||||
|
||||
ComponentName componentName = existingGameSessionRecord.getComponentName();
|
||||
|
||||
// TODO(b/207035150): Allow the game service provider to determine if a game session
|
||||
// should be created. For now we will assume all games should have a session.
|
||||
AndroidFuture<IBinder> gameSessionFuture = new AndroidFuture<IBinder>()
|
||||
@@ -211,10 +262,10 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
||||
.whenCompleteAsync((gameSessionIBinder, exception) -> {
|
||||
IGameSession gameSession = IGameSession.Stub.asInterface(gameSessionIBinder);
|
||||
if (exception != null || gameSession == null) {
|
||||
Slog.w(TAG, "Failed to create GameSession: " + gameSessionRecord,
|
||||
Slog.w(TAG, "Failed to create GameSession: " + existingGameSessionRecord,
|
||||
exception);
|
||||
synchronized (mLock) {
|
||||
destroyGameSessionLocked(sessionId);
|
||||
destroyGameSessionIfNecessaryLocked(sessionId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -239,9 +290,19 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
||||
}
|
||||
|
||||
GameSessionRecord gameSessionRecord = mGameSessions.get(sessionId);
|
||||
boolean isValidAttachRequest = true;
|
||||
if (gameSessionRecord == null) {
|
||||
Slog.w(TAG, "No associated game session record. Destroying id: " + sessionId);
|
||||
isValidAttachRequest = false;
|
||||
}
|
||||
if (gameSessionRecord != null && !gameSessionRecord.isGameSessionRequested()) {
|
||||
Slog.w(TAG,
|
||||
"Game session not requested for existing game session record. Destroying id: "
|
||||
+ sessionId);
|
||||
isValidAttachRequest = false;
|
||||
}
|
||||
|
||||
if (!isValidAttachRequest) {
|
||||
try {
|
||||
gameSession.destroy();
|
||||
} catch (RemoteException ex) {
|
||||
@@ -254,7 +315,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void destroyGameSessionLocked(int sessionId) {
|
||||
private void destroyGameSessionIfNecessaryLocked(int sessionId) {
|
||||
// TODO(b/204503192): Limit the lifespan of the game session in the Game Service provider
|
||||
// to only when the associated task is running. Right now it is possible for a task to
|
||||
// move into the background and for all associated processes to die and for the Game Session
|
||||
|
||||
@@ -25,28 +25,59 @@ import java.util.Objects;
|
||||
|
||||
final class GameSessionRecord {
|
||||
|
||||
private enum State {
|
||||
// Game task is running, but GameSession not created.
|
||||
NO_GAME_SESSION_REQUESTED,
|
||||
// Game Service provider requested a Game Session and we are in the
|
||||
// process of creating it. GameSessionRecord.getGameSession() == null;
|
||||
GAME_SESSION_REQUESTED,
|
||||
// A Game Session is created and attached.
|
||||
// GameSessionRecord.getGameSession() != null.
|
||||
GAME_SESSION_ATTACHED,
|
||||
}
|
||||
|
||||
private final int mTaskId;
|
||||
private final ComponentName mRootComponentName;
|
||||
@Nullable
|
||||
private final IGameSession mIGameSession;
|
||||
private final State mState;
|
||||
|
||||
static GameSessionRecord pendingGameSession(int taskId, ComponentName rootComponentName) {
|
||||
return new GameSessionRecord(taskId, rootComponentName, /* gameSession= */ null);
|
||||
static GameSessionRecord awaitingGameSessionRequest(int taskId,
|
||||
ComponentName rootComponentName) {
|
||||
return new GameSessionRecord(taskId, rootComponentName, /* gameSession= */ null,
|
||||
State.NO_GAME_SESSION_REQUESTED);
|
||||
}
|
||||
|
||||
private GameSessionRecord(
|
||||
int taskId,
|
||||
@NonNull ComponentName rootComponentName,
|
||||
@Nullable IGameSession gameSession) {
|
||||
@Nullable IGameSession gameSession,
|
||||
@NonNull State state) {
|
||||
this.mTaskId = taskId;
|
||||
this.mRootComponentName = rootComponentName;
|
||||
this.mIGameSession = gameSession;
|
||||
this.mState = state;
|
||||
}
|
||||
|
||||
public boolean isAwaitingGameSessionRequest() {
|
||||
return mState == State.NO_GAME_SESSION_REQUESTED;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public GameSessionRecord withGameSessionRequested() {
|
||||
return new GameSessionRecord(mTaskId, mRootComponentName, /* gameSession=*/ null,
|
||||
State.GAME_SESSION_REQUESTED);
|
||||
}
|
||||
|
||||
public boolean isGameSessionRequested() {
|
||||
return mState == State.GAME_SESSION_REQUESTED;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public GameSessionRecord withGameSession(@NonNull IGameSession gameSession) {
|
||||
Objects.requireNonNull(gameSession);
|
||||
return new GameSessionRecord(mTaskId, mRootComponentName, gameSession);
|
||||
return new GameSessionRecord(mTaskId, mRootComponentName, gameSession,
|
||||
State.GAME_SESSION_ATTACHED);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -54,6 +85,11 @@ final class GameSessionRecord {
|
||||
return mIGameSession;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ComponentName getComponentName() {
|
||||
return mRootComponentName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GameSessionRecord{"
|
||||
@@ -63,6 +99,8 @@ final class GameSessionRecord {
|
||||
+ mRootComponentName
|
||||
+ ", mIGameSession="
|
||||
+ mIGameSession
|
||||
+ ", mState="
|
||||
+ mState
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -78,11 +116,11 @@ final class GameSessionRecord {
|
||||
|
||||
GameSessionRecord that = (GameSessionRecord) o;
|
||||
return mTaskId == that.mTaskId && mRootComponentName.equals(that.mRootComponentName)
|
||||
&& Objects.equals(mIGameSession, that.mIGameSession);
|
||||
&& Objects.equals(mIGameSession, that.mIGameSession) && mState == that.mState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mTaskId, mRootComponentName, mIGameSession);
|
||||
return Objects.hash(mTaskId, mRootComponentName, mIGameSession, mState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.server.app;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@@ -35,7 +36,9 @@ import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.service.games.CreateGameSessionRequest;
|
||||
import android.service.games.GameStartedEvent;
|
||||
import android.service.games.IGameService;
|
||||
import android.service.games.IGameServiceController;
|
||||
import android.service.games.IGameSession;
|
||||
import android.service.games.IGameSessionService;
|
||||
|
||||
@@ -50,6 +53,7 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoSession;
|
||||
@@ -135,7 +139,7 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
public void start_startsGameSession() throws Exception {
|
||||
mGameServiceProviderInstance.start();
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
|
||||
assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
|
||||
@@ -146,7 +150,7 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
public void start_multipleTimes_startsGameSessionOnce() throws Exception {
|
||||
mGameServiceProviderInstance.start();
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
|
||||
assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
|
||||
@@ -167,7 +171,7 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
mGameServiceProviderInstance.start();
|
||||
mGameServiceProviderInstance.stop();
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).disconnected();
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
|
||||
@@ -183,9 +187,9 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
mGameServiceProviderInstance.start();
|
||||
mGameServiceProviderInstance.stop();
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).disconnected();
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).disconnected();
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
|
||||
@@ -199,7 +203,7 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
mGameServiceProviderInstance.stop();
|
||||
mGameServiceProviderInstance.stop();
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).disconnected();
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
|
||||
@@ -231,7 +235,7 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
mGameServiceProviderInstance.stop();
|
||||
dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).disconnected();
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
|
||||
@@ -244,7 +248,7 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
mGameServiceProviderInstance.start();
|
||||
dispatchTaskCreated(10, APP_A_MAIN_ACTIVITY);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
|
||||
assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
|
||||
@@ -256,7 +260,7 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
mGameServiceProviderInstance.start();
|
||||
dispatchTaskCreated(10, null);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
|
||||
assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
|
||||
@@ -264,18 +268,84 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gameTaskStarted_createsGameSession() throws Exception {
|
||||
public void gameSessionRequested_withoutTaskDispatch_ignoredAndDoesNotCrash() throws Exception {
|
||||
mGameServiceProviderInstance.start();
|
||||
ArgumentCaptor<IGameServiceController> controllerArgumentCaptor = ArgumentCaptor.forClass(
|
||||
IGameServiceController.class);
|
||||
verify(mMockGameService).connected(controllerArgumentCaptor.capture());
|
||||
controllerArgumentCaptor.getValue().createGameSession(10);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
|
||||
assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
|
||||
assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gameTaskStarted_noSessionRequest_callsStartGame() throws Exception {
|
||||
mGameServiceProviderInstance.start();
|
||||
dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(10, GAME_A_PACKAGE)));
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
|
||||
assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
|
||||
assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gameTaskStartedAndSessionRequested_createsGameSession() throws Exception {
|
||||
CreateGameSessionRequest createGameSessionRequest =
|
||||
new CreateGameSessionRequest(10, GAME_A_PACKAGE);
|
||||
Supplier<AndroidFuture<IBinder>> gameSession10Future =
|
||||
captureCreateGameSessionFuture(createGameSessionRequest);
|
||||
|
||||
mGameServiceProviderInstance.start();
|
||||
dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
|
||||
ArgumentCaptor<IGameServiceController> controllerArgumentCaptor = ArgumentCaptor.forClass(
|
||||
IGameServiceController.class);
|
||||
verify(mMockGameService).connected(controllerArgumentCaptor.capture());
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(10, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession10 = new IGameSessionStub();
|
||||
gameSession10Future.get().complete(gameSession10);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(10, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest), any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(gameSession10.mIsDestroyed).isFalse();
|
||||
assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
|
||||
assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
|
||||
assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isTrue();
|
||||
assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gameTaskStartedAndSessionRequested_secondSessionRequest_ignoredAndDoesNotCrash()
|
||||
throws Exception {
|
||||
CreateGameSessionRequest createGameSessionRequest =
|
||||
new CreateGameSessionRequest(10, GAME_A_PACKAGE);
|
||||
Supplier<AndroidFuture<IBinder>> gameSession10Future =
|
||||
captureCreateGameSessionFuture(createGameSessionRequest);
|
||||
|
||||
mGameServiceProviderInstance.start();
|
||||
ArgumentCaptor<IGameServiceController> controllerArgumentCaptor = ArgumentCaptor.forClass(
|
||||
IGameServiceController.class);
|
||||
verify(mMockGameService).connected(controllerArgumentCaptor.capture());
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(10, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession10 = new IGameSessionStub();
|
||||
gameSession10Future.get().complete(gameSession10);
|
||||
|
||||
controllerArgumentCaptor.getValue().createGameSession(10);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(10, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest), any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(gameSession10.mIsDestroyed).isFalse();
|
||||
@@ -294,12 +364,18 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
captureCreateGameSessionFuture(createGameSessionRequest);
|
||||
|
||||
mGameServiceProviderInstance.start();
|
||||
dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
|
||||
ArgumentCaptor<IGameServiceController> controllerArgumentCaptor = ArgumentCaptor.forClass(
|
||||
IGameServiceController.class);
|
||||
verify(mMockGameService).connected(controllerArgumentCaptor.capture());
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(10, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
dispatchTaskRemoved(10);
|
||||
IGameSessionStub gameSession10 = new IGameSessionStub();
|
||||
gameSession10Future.get().complete(gameSession10);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(10, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest), any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(gameSession10.mIsDestroyed).isTrue();
|
||||
@@ -317,12 +393,18 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
captureCreateGameSessionFuture(createGameSessionRequest);
|
||||
|
||||
mGameServiceProviderInstance.start();
|
||||
dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
|
||||
ArgumentCaptor<IGameServiceController> controllerArgumentCaptor = ArgumentCaptor.forClass(
|
||||
IGameServiceController.class);
|
||||
verify(mMockGameService).connected(controllerArgumentCaptor.capture());
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(10, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession10 = new IGameSessionStub();
|
||||
gameSession10Future.get().complete(gameSession10);
|
||||
dispatchTaskRemoved(10);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(10, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest), any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(gameSession10.mIsDestroyed).isTrue();
|
||||
@@ -333,7 +415,8 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gameTaskStarted_multipleTimes_createsMultipleGameSessions() throws Exception {
|
||||
public void gameTaskStartedAndSessionRequested_multipleTimes_createsMultipleGameSessions()
|
||||
throws Exception {
|
||||
CreateGameSessionRequest createGameSessionRequest10 =
|
||||
new CreateGameSessionRequest(10, GAME_A_PACKAGE);
|
||||
Supplier<AndroidFuture<IBinder>> gameSession10Future =
|
||||
@@ -345,16 +428,25 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
captureCreateGameSessionFuture(createGameSessionRequest11);
|
||||
|
||||
mGameServiceProviderInstance.start();
|
||||
dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
|
||||
ArgumentCaptor<IGameServiceController> controllerArgumentCaptor = ArgumentCaptor.forClass(
|
||||
IGameServiceController.class);
|
||||
verify(mMockGameService).connected(controllerArgumentCaptor.capture());
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(10, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession10 = new IGameSessionStub();
|
||||
gameSession10Future.get().complete(gameSession10);
|
||||
|
||||
dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(11, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession11 = new IGameSessionStub();
|
||||
gameSession11Future.get().complete(gameSession11);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(10, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(11, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(gameSession10.mIsDestroyed).isFalse();
|
||||
@@ -365,6 +457,40 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gameTaskStartedTwice_sessionRequestedSecondTimeOnly_createsOneGameSessions()
|
||||
throws Exception {
|
||||
CreateGameSessionRequest createGameSessionRequest11 =
|
||||
new CreateGameSessionRequest(11, GAME_A_PACKAGE);
|
||||
Supplier<AndroidFuture<IBinder>> gameSession11Future =
|
||||
captureCreateGameSessionFuture(createGameSessionRequest11);
|
||||
|
||||
// The game task is started twice, but a session is requested only for the second one.
|
||||
mGameServiceProviderInstance.start();
|
||||
ArgumentCaptor<IGameServiceController> controllerArgumentCaptor = ArgumentCaptor.forClass(
|
||||
IGameServiceController.class);
|
||||
verify(mMockGameService).connected(controllerArgumentCaptor.capture());
|
||||
dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
|
||||
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(11, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession11 = new IGameSessionStub();
|
||||
gameSession11Future.get().complete(gameSession11);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(10, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(11, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(gameSession11.mIsDestroyed).isFalse();
|
||||
assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
|
||||
assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
|
||||
assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isTrue();
|
||||
assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gameTaskRemoved_afterMultipleCreated_destroysOnlyThatGameSession()
|
||||
throws Exception {
|
||||
@@ -379,18 +505,27 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
captureCreateGameSessionFuture(createGameSessionRequest11);
|
||||
|
||||
mGameServiceProviderInstance.start();
|
||||
dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
|
||||
ArgumentCaptor<IGameServiceController> controllerArgumentCaptor = ArgumentCaptor.forClass(
|
||||
IGameServiceController.class);
|
||||
verify(mMockGameService).connected(controllerArgumentCaptor.capture());
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(10, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession10 = new IGameSessionStub();
|
||||
gameSession10Future.get().complete(gameSession10);
|
||||
|
||||
dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(11, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession11 = new IGameSessionStub();
|
||||
gameSession11Future.get().complete(gameSession11);
|
||||
|
||||
dispatchTaskRemoved(10);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(10, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(11, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(gameSession10.mIsDestroyed).isTrue();
|
||||
@@ -414,19 +549,28 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
captureCreateGameSessionFuture(createGameSessionRequest11);
|
||||
|
||||
mGameServiceProviderInstance.start();
|
||||
dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
|
||||
ArgumentCaptor<IGameServiceController> controllerArgumentCaptor = ArgumentCaptor.forClass(
|
||||
IGameServiceController.class);
|
||||
verify(mMockGameService).connected(controllerArgumentCaptor.capture());
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(10, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession10 = new IGameSessionStub();
|
||||
gameSession10Future.get().complete(gameSession10);
|
||||
|
||||
dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(11, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession11 = new IGameSessionStub();
|
||||
gameSession11Future.get().complete(gameSession11);
|
||||
|
||||
dispatchTaskRemoved(10);
|
||||
dispatchTaskRemoved(11);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(10, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(11, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(gameSession10.mIsDestroyed).isTrue();
|
||||
@@ -438,7 +582,7 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gameTasksCreated_afterAllPreviousSessionsDestroyed_createsSession()
|
||||
public void gameTasksCreatedAndSessionsReq_afterAllPreviousSessionsDestroyed_createsSession()
|
||||
throws Exception {
|
||||
CreateGameSessionRequest createGameSessionRequest10 =
|
||||
new CreateGameSessionRequest(10, GAME_A_PACKAGE);
|
||||
@@ -456,24 +600,36 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
captureCreateGameSessionFuture(createGameSessionRequest12);
|
||||
|
||||
mGameServiceProviderInstance.start();
|
||||
dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
|
||||
ArgumentCaptor<IGameServiceController> controllerArgumentCaptor = ArgumentCaptor.forClass(
|
||||
IGameServiceController.class);
|
||||
verify(mMockGameService).connected(controllerArgumentCaptor.capture());
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(10, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession10 = new IGameSessionStub();
|
||||
gameSession10Future.get().complete(gameSession10);
|
||||
|
||||
dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(11, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession11 = new IGameSessionStub();
|
||||
gameSession11Future.get().complete(gameSession11);
|
||||
|
||||
dispatchTaskRemoved(10);
|
||||
dispatchTaskRemoved(11);
|
||||
|
||||
dispatchTaskCreated(12, GAME_A_MAIN_ACTIVITY);
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(12, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession12 = new IGameSessionStub();
|
||||
gameSession11Future.get().complete(gameSession12);
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(10, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(11, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(12, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest12), any());
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
assertThat(gameSession10.mIsDestroyed).isTrue();
|
||||
@@ -498,16 +654,25 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
captureCreateGameSessionFuture(createGameSessionRequest11);
|
||||
|
||||
mGameServiceProviderInstance.start();
|
||||
dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
|
||||
ArgumentCaptor<IGameServiceController> controllerArgumentCaptor = ArgumentCaptor.forClass(
|
||||
IGameServiceController.class);
|
||||
verify(mMockGameService).connected(controllerArgumentCaptor.capture());
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(10, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession10 = new IGameSessionStub();
|
||||
gameSession10Future.get().complete(gameSession10);
|
||||
dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
|
||||
dispatchTaskCreatedAndTriggerSessionRequest(11, GAME_A_MAIN_ACTIVITY,
|
||||
controllerArgumentCaptor.getValue());
|
||||
IGameSessionStub gameSession11 = new IGameSessionStub();
|
||||
gameSession11Future.get().complete(gameSession11);
|
||||
mGameServiceProviderInstance.stop();
|
||||
|
||||
mInOrder.verify(mMockGameService).connected();
|
||||
mInOrder.verify(mMockGameService).connected(any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(10, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
|
||||
mInOrder.verify(mMockGameService).gameStarted(
|
||||
eq(new GameStartedEvent(11, GAME_A_PACKAGE)));
|
||||
mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
|
||||
mInOrder.verify(mMockGameService).disconnected();
|
||||
mInOrder.verifyNoMoreInteractions();
|
||||
@@ -536,6 +701,13 @@ public final class GameServiceProviderInstanceImplTest {
|
||||
});
|
||||
}
|
||||
|
||||
private void dispatchTaskCreatedAndTriggerSessionRequest(int taskId,
|
||||
@Nullable ComponentName componentName, IGameServiceController gameServiceController)
|
||||
throws Exception {
|
||||
dispatchTaskCreated(taskId, componentName);
|
||||
gameServiceController.createGameSession(taskId);
|
||||
}
|
||||
|
||||
private void dispatchTaskCreated(int taskId, @Nullable ComponentName componentName) {
|
||||
dispatchTaskChangeEvent(taskStackListener -> {
|
||||
taskStackListener.onTaskCreated(taskId, componentName);
|
||||
|
||||
Reference in New Issue
Block a user