From f2579028edfc5208b3c62cc56cbca5afb855efa0 Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Thu, 3 Nov 2022 15:32:37 -0700 Subject: [PATCH] Add custom game mode Bug: b/243448953 Test: atest GameManagerTests Change-Id: Ifda3e97c737b7bfdc4ffcf3cdd9fc7f24fe5ed5b --- core/api/current.txt | 1 + core/java/android/app/GameManager.java | 50 ++++++++++++++++--- .../src/android/app/GameManagerTests.java | 8 +++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index ee04a461eff57..7ff07e4fcb90d 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -5611,6 +5611,7 @@ package android.app { method public int getGameMode(); method public void setGameState(@NonNull android.app.GameState); field public static final int GAME_MODE_BATTERY = 3; // 0x3 + field public static final int GAME_MODE_CUSTOM = 4; // 0x4 field public static final int GAME_MODE_PERFORMANCE = 2; // 0x2 field public static final int GAME_MODE_STANDARD = 1; // 0x1 field public static final int GAME_MODE_UNSUPPORTED = 0; // 0x0 diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java index a5adaa4e0196b..aac163c28cea9 100644 --- a/core/java/android/app/GameManager.java +++ b/core/java/android/app/GameManager.java @@ -26,6 +26,9 @@ import android.annotation.SystemService; import android.annotation.TestApi; import android.annotation.UserHandleAware; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Build; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; @@ -51,6 +54,7 @@ public final class GameManager { GAME_MODE_STANDARD, // 1 GAME_MODE_PERFORMANCE, // 2 GAME_MODE_BATTERY, // 3 + GAME_MODE_CUSTOM, // 4 }) @Retention(RetentionPolicy.SOURCE) public @interface GameMode { @@ -79,6 +83,15 @@ public final class GameManager { */ public static final int GAME_MODE_BATTERY = 3; + /** + * Custom game mode that has user-provided configuration overrides. + *

+ * Custom game mode is expected to be handled only by the platform using users' + * preferred config. It is currently not allowed to opt in custom mode in game mode XML file nor + * expected to perform app-based optimizations when activated. + */ + public static final int GAME_MODE_CUSTOM = 4; + GameManager(Context context, Handler handler) throws ServiceNotFoundException { mContext = context; mService = IGameManagerService.Stub.asInterface( @@ -93,19 +106,23 @@ public final class GameManager { * application is not a game, always return {@link #GAME_MODE_UNSUPPORTED}. *

* Developers should call this API every time the application is resumed. + *

+ * If a game's targetSdkVersion is {@link android.os.Build.VERSION_CODES#TIRAMISU} + * or lower, and when the game mode is set to {@link #GAME_MODE_CUSTOM} which is available in + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or newer, this API will return + * {@link #GAME_MODE_STANDARD} instead for backward compatibility. */ public @GameMode int getGameMode() { - try { - return mService.getGameMode(mContext.getPackageName(), mContext.getUserId()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getGameModeImpl(mContext.getPackageName(), + mContext.getApplicationInfo().targetSdkVersion); } /** * Gets the game mode for the given package. *

* The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}. + *

+ * Also see {@link #getGameMode()} on how it handles SDK version compatibility. * * @hide */ @@ -113,11 +130,32 @@ public final class GameManager { @UserHandleAware @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) public @GameMode int getGameMode(@NonNull String packageName) { + final int targetSdkVersion; try { - return mService.getGameMode(packageName, mContext.getUserId()); + final ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo( + packageName, PackageManager.ApplicationInfoFlags.of(0)); + targetSdkVersion = applicationInfo.targetSdkVersion; + } catch (PackageManager.NameNotFoundException ex) { + return GAME_MODE_UNSUPPORTED; + } + return getGameModeImpl(packageName, targetSdkVersion); + } + + // This target SDK version check can be performed against any game by a privileged app, and + // we don't want a binder call each time to check on behalf of an app using CompatChange. + @SuppressWarnings("AndroidFrameworkCompatChange") + private @GameMode int getGameModeImpl(@NonNull String packageName, int targetSdkVersion) { + final int gameMode; + try { + gameMode = mService.getGameMode(packageName, + mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } + if (gameMode == GAME_MODE_CUSTOM && targetSdkVersion <= Build.VERSION_CODES.TIRAMISU) { + return GAME_MODE_STANDARD; + } + return gameMode; } /** diff --git a/core/tests/GameManagerTests/src/android/app/GameManagerTests.java b/core/tests/GameManagerTests/src/android/app/GameManagerTests.java index baecc8c4650e6..4664ec71b470c 100644 --- a/core/tests/GameManagerTests/src/android/app/GameManagerTests.java +++ b/core/tests/GameManagerTests/src/android/app/GameManagerTests.java @@ -63,6 +63,10 @@ public final class GameManagerTests { mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE); assertEquals(GameManager.GAME_MODE_PERFORMANCE, mGameManager.getGameMode()); + + mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_CUSTOM); + assertEquals(GameManager.GAME_MODE_CUSTOM, + mGameManager.getGameMode()); } @Test @@ -77,5 +81,9 @@ public final class GameManagerTests { mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE); assertEquals(GameManager.GAME_MODE_PERFORMANCE, mGameManager.getGameMode(mPackageName)); + + mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_CUSTOM); + assertEquals(GameManager.GAME_MODE_CUSTOM, + mGameManager.getGameMode(mPackageName)); } }