Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2579028 authored by Xiang Wang's avatar Xiang Wang
Browse files

Add custom game mode

Bug: b/243448953
Test: atest GameManagerTests
Change-Id: Ifda3e97c737b7bfdc4ffcf3cdd9fc7f24fe5ed5b
parent 9c5ce9d0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+44 −6
Original line number Diff line number Diff line
@@ -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.
     * <p>
     * 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}.
     * <p>
     * Developers should call this API every time the application is resumed.
     * <p>
     * If a game's <code>targetSdkVersion</code> 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.
     * <p>
     * The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}.
     * <p>
     * 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;
    }

    /**
+8 −0
Original line number Diff line number Diff line
@@ -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));
    }
}