Loading core/api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -10905,6 +10905,7 @@ package android.service.games { ctor public GameSession(); method public void onCreate(); method public void onDestroy(); method public void setTaskOverlayView(@NonNull android.view.View, @NonNull android.view.ViewGroup.LayoutParams); } public abstract class GameSessionService extends android.app.Service { core/java/android/service/games/CreateGameSessionResult.aidl 0 → 100644 +23 −0 Original line number Diff line number Diff line /* * 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 CreateGameSessionResult; core/java/android/service/games/CreateGameSessionResult.java 0 → 100644 +84 −0 Original line number Diff line number Diff line /* * 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.Hide; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import android.view.SurfaceControlViewHost; /** * Internal result object that contains the successful creation of a game session. * * @see IGameSessionService#create(CreateGameSessionRequest, GameSessionViewHostConfiguration, * com.android.internal.infra.AndroidFuture) * @hide */ @Hide public final class CreateGameSessionResult implements Parcelable { @NonNull public static final Parcelable.Creator<CreateGameSessionResult> CREATOR = new Parcelable.Creator<CreateGameSessionResult>() { @Override public CreateGameSessionResult createFromParcel(Parcel source) { return new CreateGameSessionResult( IGameSession.Stub.asInterface(source.readStrongBinder()), source.readParcelable( SurfaceControlViewHost.SurfacePackage.class.getClassLoader(), SurfaceControlViewHost.SurfacePackage.class)); } @Override public CreateGameSessionResult[] newArray(int size) { return new CreateGameSessionResult[0]; } }; private final IGameSession mGameSession; private final SurfaceControlViewHost.SurfacePackage mSurfacePackage; public CreateGameSessionResult( @NonNull IGameSession gameSession, @NonNull SurfaceControlViewHost.SurfacePackage surfacePackage) { mGameSession = gameSession; mSurfacePackage = surfacePackage; } @NonNull public IGameSession getGameSession() { return mGameSession; } @NonNull public SurfaceControlViewHost.SurfacePackage getSurfacePackage() { return mSurfacePackage; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeStrongBinder(mGameSession.asBinder()); dest.writeParcelable(mSurfacePackage, flags); } } core/java/android/service/games/GameSession.java +73 −2 Original line number Diff line number Diff line Loading @@ -16,8 +16,17 @@ package android.service.games; import android.annotation.Hide; import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Handler; import android.view.SurfaceControlViewHost; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import com.android.internal.util.function.pooled.PooledLambda; Loading @@ -41,12 +50,29 @@ public abstract class GameSession { } }; private GameSessionRootView mGameSessionRootView; private SurfaceControlViewHost mSurfaceControlViewHost; @Hide void attach( @NonNull Context context, @NonNull SurfaceControlViewHost surfaceControlViewHost, int widthPx, int heightPx) { mSurfaceControlViewHost = surfaceControlViewHost; mGameSessionRootView = new GameSessionRootView(context, mSurfaceControlViewHost); surfaceControlViewHost.setView(mGameSessionRootView, widthPx, heightPx); } @Hide void doCreate() { onCreate(); } @Hide void doDestroy() { onDestroy(); mSurfaceControlViewHost.release(); } /** Loading @@ -54,12 +80,57 @@ public abstract class GameSession { * * This should be used perform any setup required now that the game session is created. */ public void onCreate() {} public void onCreate() { } /** * Finalizer called when the game session is ending. * * This should be used to perform any cleanup before the game session is destroyed. */ public void onDestroy() {} public void onDestroy() { } /** * Sets the task overlay content to an explicit view. This view is placed directly into the game * session's task overlay view hierarchy. It can itself be a complex view hierarchy. The size * the task overlay view will always match the dimensions of the associated task's window. The * {@code View} may not be cleared once set, but may be replaced by invoking * {@link #setTaskOverlayView(View, ViewGroup.LayoutParams)} again. * * @param view The desired content to display. * @param layoutParams Layout parameters for the view. */ public void setTaskOverlayView( @NonNull View view, @NonNull ViewGroup.LayoutParams layoutParams) { mGameSessionRootView.removeAllViews(); mGameSessionRootView.addView(view, layoutParams); } /** * Root view of the {@link SurfaceControlViewHost} associated with the {@link GameSession} * instance. It is responsible for observing changes in the size of the window and resizing * itself to match. */ private static final class GameSessionRootView extends FrameLayout { private final SurfaceControlViewHost mSurfaceControlViewHost; GameSessionRootView(@NonNull Context context, SurfaceControlViewHost surfaceControlViewHost) { super(context); mSurfaceControlViewHost = surfaceControlViewHost; } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // TODO(b/204504596): Investigate skipping the relayout in cases where the size has // not changed. Rect bounds = newConfig.windowConfiguration.getBounds(); mSurfaceControlViewHost.relayout(bounds.width(), bounds.height()); } } } core/java/android/service/games/GameSessionService.java +43 −4 Original line number Diff line number Diff line Loading @@ -22,8 +22,12 @@ import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; import android.hardware.display.DisplayManager; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.view.Display; import android.view.SurfaceControlViewHost; import com.android.internal.infra.AndroidFuture; import com.android.internal.util.function.pooled.PooledLambda; Loading Loading @@ -62,15 +66,26 @@ public abstract class GameSessionService extends Service { private final IGameSessionService mInterface = new IGameSessionService.Stub() { @Override public void create(CreateGameSessionRequest createGameSessionRequest, public void create( CreateGameSessionRequest createGameSessionRequest, GameSessionViewHostConfiguration gameSessionViewHostConfiguration, AndroidFuture gameSessionFuture) { Handler.getMain().post(PooledLambda.obtainRunnable( GameSessionService::doCreate, GameSessionService.this, createGameSessionRequest, gameSessionViewHostConfiguration, gameSessionFuture)); } }; private DisplayManager mDisplayManager; @Override public void onCreate() { super.onCreate(); mDisplayManager = this.getSystemService(DisplayManager.class); } @Override @Nullable public final IBinder onBind(@Nullable Intent intent) { Loading @@ -85,12 +100,36 @@ public abstract class GameSessionService extends Service { return mInterface.asBinder(); } private void doCreate(CreateGameSessionRequest createGameSessionRequest, AndroidFuture<IBinder> gameSessionFuture) { private void doCreate( CreateGameSessionRequest createGameSessionRequest, GameSessionViewHostConfiguration gameSessionViewHostConfiguration, AndroidFuture<CreateGameSessionResult> createGameSessionResultFuture) { GameSession gameSession = onNewSession(createGameSessionRequest); Objects.requireNonNull(gameSession); gameSessionFuture.complete(gameSession.mInterface.asBinder()); Display display = mDisplayManager.getDisplay(gameSessionViewHostConfiguration.mDisplayId); if (display == null) { createGameSessionResultFuture.completeExceptionally( new IllegalStateException("No display found for id: " + gameSessionViewHostConfiguration.mDisplayId)); return; } IBinder hostToken = new Binder(); SurfaceControlViewHost surfaceControlViewHost = new SurfaceControlViewHost(this, display, hostToken); gameSession.attach(this, surfaceControlViewHost, gameSessionViewHostConfiguration.mWidthPx, gameSessionViewHostConfiguration.mHeightPx); CreateGameSessionResult createGameSessionResult = new CreateGameSessionResult(gameSession.mInterface, surfaceControlViewHost.getSurfacePackage()); createGameSessionResultFuture.complete(createGameSessionResult); gameSession.doCreate(); } Loading Loading
core/api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -10905,6 +10905,7 @@ package android.service.games { ctor public GameSession(); method public void onCreate(); method public void onDestroy(); method public void setTaskOverlayView(@NonNull android.view.View, @NonNull android.view.ViewGroup.LayoutParams); } public abstract class GameSessionService extends android.app.Service {
core/java/android/service/games/CreateGameSessionResult.aidl 0 → 100644 +23 −0 Original line number Diff line number Diff line /* * 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 CreateGameSessionResult;
core/java/android/service/games/CreateGameSessionResult.java 0 → 100644 +84 −0 Original line number Diff line number Diff line /* * 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.Hide; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import android.view.SurfaceControlViewHost; /** * Internal result object that contains the successful creation of a game session. * * @see IGameSessionService#create(CreateGameSessionRequest, GameSessionViewHostConfiguration, * com.android.internal.infra.AndroidFuture) * @hide */ @Hide public final class CreateGameSessionResult implements Parcelable { @NonNull public static final Parcelable.Creator<CreateGameSessionResult> CREATOR = new Parcelable.Creator<CreateGameSessionResult>() { @Override public CreateGameSessionResult createFromParcel(Parcel source) { return new CreateGameSessionResult( IGameSession.Stub.asInterface(source.readStrongBinder()), source.readParcelable( SurfaceControlViewHost.SurfacePackage.class.getClassLoader(), SurfaceControlViewHost.SurfacePackage.class)); } @Override public CreateGameSessionResult[] newArray(int size) { return new CreateGameSessionResult[0]; } }; private final IGameSession mGameSession; private final SurfaceControlViewHost.SurfacePackage mSurfacePackage; public CreateGameSessionResult( @NonNull IGameSession gameSession, @NonNull SurfaceControlViewHost.SurfacePackage surfacePackage) { mGameSession = gameSession; mSurfacePackage = surfacePackage; } @NonNull public IGameSession getGameSession() { return mGameSession; } @NonNull public SurfaceControlViewHost.SurfacePackage getSurfacePackage() { return mSurfacePackage; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeStrongBinder(mGameSession.asBinder()); dest.writeParcelable(mSurfacePackage, flags); } }
core/java/android/service/games/GameSession.java +73 −2 Original line number Diff line number Diff line Loading @@ -16,8 +16,17 @@ package android.service.games; import android.annotation.Hide; import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Handler; import android.view.SurfaceControlViewHost; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import com.android.internal.util.function.pooled.PooledLambda; Loading @@ -41,12 +50,29 @@ public abstract class GameSession { } }; private GameSessionRootView mGameSessionRootView; private SurfaceControlViewHost mSurfaceControlViewHost; @Hide void attach( @NonNull Context context, @NonNull SurfaceControlViewHost surfaceControlViewHost, int widthPx, int heightPx) { mSurfaceControlViewHost = surfaceControlViewHost; mGameSessionRootView = new GameSessionRootView(context, mSurfaceControlViewHost); surfaceControlViewHost.setView(mGameSessionRootView, widthPx, heightPx); } @Hide void doCreate() { onCreate(); } @Hide void doDestroy() { onDestroy(); mSurfaceControlViewHost.release(); } /** Loading @@ -54,12 +80,57 @@ public abstract class GameSession { * * This should be used perform any setup required now that the game session is created. */ public void onCreate() {} public void onCreate() { } /** * Finalizer called when the game session is ending. * * This should be used to perform any cleanup before the game session is destroyed. */ public void onDestroy() {} public void onDestroy() { } /** * Sets the task overlay content to an explicit view. This view is placed directly into the game * session's task overlay view hierarchy. It can itself be a complex view hierarchy. The size * the task overlay view will always match the dimensions of the associated task's window. The * {@code View} may not be cleared once set, but may be replaced by invoking * {@link #setTaskOverlayView(View, ViewGroup.LayoutParams)} again. * * @param view The desired content to display. * @param layoutParams Layout parameters for the view. */ public void setTaskOverlayView( @NonNull View view, @NonNull ViewGroup.LayoutParams layoutParams) { mGameSessionRootView.removeAllViews(); mGameSessionRootView.addView(view, layoutParams); } /** * Root view of the {@link SurfaceControlViewHost} associated with the {@link GameSession} * instance. It is responsible for observing changes in the size of the window and resizing * itself to match. */ private static final class GameSessionRootView extends FrameLayout { private final SurfaceControlViewHost mSurfaceControlViewHost; GameSessionRootView(@NonNull Context context, SurfaceControlViewHost surfaceControlViewHost) { super(context); mSurfaceControlViewHost = surfaceControlViewHost; } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // TODO(b/204504596): Investigate skipping the relayout in cases where the size has // not changed. Rect bounds = newConfig.windowConfiguration.getBounds(); mSurfaceControlViewHost.relayout(bounds.width(), bounds.height()); } } }
core/java/android/service/games/GameSessionService.java +43 −4 Original line number Diff line number Diff line Loading @@ -22,8 +22,12 @@ import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; import android.hardware.display.DisplayManager; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.view.Display; import android.view.SurfaceControlViewHost; import com.android.internal.infra.AndroidFuture; import com.android.internal.util.function.pooled.PooledLambda; Loading Loading @@ -62,15 +66,26 @@ public abstract class GameSessionService extends Service { private final IGameSessionService mInterface = new IGameSessionService.Stub() { @Override public void create(CreateGameSessionRequest createGameSessionRequest, public void create( CreateGameSessionRequest createGameSessionRequest, GameSessionViewHostConfiguration gameSessionViewHostConfiguration, AndroidFuture gameSessionFuture) { Handler.getMain().post(PooledLambda.obtainRunnable( GameSessionService::doCreate, GameSessionService.this, createGameSessionRequest, gameSessionViewHostConfiguration, gameSessionFuture)); } }; private DisplayManager mDisplayManager; @Override public void onCreate() { super.onCreate(); mDisplayManager = this.getSystemService(DisplayManager.class); } @Override @Nullable public final IBinder onBind(@Nullable Intent intent) { Loading @@ -85,12 +100,36 @@ public abstract class GameSessionService extends Service { return mInterface.asBinder(); } private void doCreate(CreateGameSessionRequest createGameSessionRequest, AndroidFuture<IBinder> gameSessionFuture) { private void doCreate( CreateGameSessionRequest createGameSessionRequest, GameSessionViewHostConfiguration gameSessionViewHostConfiguration, AndroidFuture<CreateGameSessionResult> createGameSessionResultFuture) { GameSession gameSession = onNewSession(createGameSessionRequest); Objects.requireNonNull(gameSession); gameSessionFuture.complete(gameSession.mInterface.asBinder()); Display display = mDisplayManager.getDisplay(gameSessionViewHostConfiguration.mDisplayId); if (display == null) { createGameSessionResultFuture.completeExceptionally( new IllegalStateException("No display found for id: " + gameSessionViewHostConfiguration.mDisplayId)); return; } IBinder hostToken = new Binder(); SurfaceControlViewHost surfaceControlViewHost = new SurfaceControlViewHost(this, display, hostToken); gameSession.attach(this, surfaceControlViewHost, gameSessionViewHostConfiguration.mWidthPx, gameSessionViewHostConfiguration.mHeightPx); CreateGameSessionResult createGameSessionResult = new CreateGameSessionResult(gameSession.mInterface, surfaceControlViewHost.getSurfacePackage()); createGameSessionResultFuture.complete(createGameSessionResult); gameSession.doCreate(); } Loading