1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app;
18 
19 import android.annotation.NonNull;
20 import android.annotation.SystemApi;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.util.ArrayMap;
24 
25 import androidx.annotation.Nullable;
26 
27 import com.android.internal.annotations.VisibleForTesting;
28 
29 import java.util.Arrays;
30 import java.util.Map;
31 
32 /**
33  * GameModeInfo returned from {@link GameManager#getGameModeInfo(String)}.
34  *
35  * Developers can enable game modes or interventions by adding
36  * <pre>{@code
37  * <meta-data android:name="android.game_mode_intervention"
38  *   android:resource="@xml/GAME_MODE_CONFIG_FILE" />
39  * }</pre>
40  * to the <pre>{@code <application>}</pre>, where the GAME_MODE_CONFIG_FILE is an XML file that
41  * specifies the game mode enablement and intervention configuration:
42  * <pre>{@code
43  * <game-mode-config xmlns:android="http://schemas.android.com/apk/res/android"
44  *   android:gameModePerformance="true"
45  *   android:gameModeBattery="false"
46  *   android:allowGameDownscaling="true"
47  *   android:allowGameFpsOverride="false"
48  * />
49  * }</pre>
50  *
51  * @hide
52  */
53 @SystemApi
54 public final class GameModeInfo implements Parcelable {
55 
56     public static final @NonNull Creator<GameModeInfo> CREATOR = new Creator<GameModeInfo>() {
57         @Override
58         public GameModeInfo createFromParcel(Parcel in) {
59             return new GameModeInfo(in);
60         }
61 
62         @Override
63         public GameModeInfo[] newArray(int size) {
64             return new GameModeInfo[size];
65         }
66     };
67 
68     /**
69      * Builder for {@link GameModeInfo}.
70      *
71      * @hide
72      */
73     @SystemApi
74     public static final class Builder {
75         /** Constructs a new Builder for a game mode info. */
Builder()76         public Builder() {
77         }
78 
79         /**
80          * Sets the available game modes.
81          */
82         @NonNull
setAvailableGameModes( @onNull @ameManager.GameMode int[] availableGameModes)83         public GameModeInfo.Builder setAvailableGameModes(
84                 @NonNull @GameManager.GameMode int[] availableGameModes) {
85             mAvailableGameModes = availableGameModes;
86             return this;
87         }
88 
89         /**
90          * Sets the overridden game modes.
91          */
92         @NonNull
setOverriddenGameModes( @onNull @ameManager.GameMode int[] overriddenGameModes)93         public GameModeInfo.Builder setOverriddenGameModes(
94                 @NonNull @GameManager.GameMode int[] overriddenGameModes) {
95             mOverriddenGameModes = overriddenGameModes;
96             return this;
97         }
98 
99         /**
100          * Sets the active game mode.
101          */
102         @NonNull
setActiveGameMode( @onNull @ameManager.GameMode int activeGameMode)103         public GameModeInfo.Builder setActiveGameMode(
104                 @NonNull @GameManager.GameMode int activeGameMode) {
105             mActiveGameMode = activeGameMode;
106             return this;
107         }
108 
109         /**
110          * Sets the downscaling intervention flag.
111          */
112         @NonNull
setDownscalingAllowed(boolean allowed)113         public GameModeInfo.Builder setDownscalingAllowed(boolean allowed) {
114             mIsDownscalingAllowed = allowed;
115             return this;
116         }
117 
118         /**
119          * Sets the FPS override flag.
120          */
121         @NonNull
setFpsOverrideAllowed(boolean allowed)122         public GameModeInfo.Builder setFpsOverrideAllowed(boolean allowed) {
123             mIsFpsOverrideAllowed = allowed;
124             return this;
125         }
126 
127         /**
128          * Sets the GameModeConfiguration for a game mode.
129          */
130         @NonNull
setGameModeConfiguration( @ameManager.GameMode int gameMode, @NonNull GameModeConfiguration gameModeConfiguration)131         public GameModeInfo.Builder setGameModeConfiguration(
132                 @GameManager.GameMode int gameMode,
133                 @NonNull GameModeConfiguration gameModeConfiguration) {
134             mConfigMap.put(gameMode, gameModeConfiguration);
135             return this;
136         }
137 
138         /**
139          * Builds a GameModeInfo.
140          */
141         @NonNull
build()142         public GameModeInfo build() {
143             return new GameModeInfo(mActiveGameMode, mAvailableGameModes, mOverriddenGameModes,
144                     mIsDownscalingAllowed, mIsFpsOverrideAllowed, mConfigMap);
145         }
146 
147         private @GameManager.GameMode int[] mAvailableGameModes = new int[]{};
148         private @GameManager.GameMode int[] mOverriddenGameModes = new int[]{};
149         private @GameManager.GameMode int mActiveGameMode;
150         private boolean mIsDownscalingAllowed;
151         private boolean mIsFpsOverrideAllowed;
152         private Map<Integer, GameModeConfiguration> mConfigMap = new ArrayMap<>();
153     }
154 
155     /**
156      * Creates a game mode info.
157      *
158      * @deprecated Use the {@link Builder} instead.
159      */
GameModeInfo(@ameManager.GameMode int activeGameMode, @NonNull @GameManager.GameMode int[] availableGameModes)160     public GameModeInfo(@GameManager.GameMode int activeGameMode,
161             @NonNull @GameManager.GameMode int[] availableGameModes) {
162         this(activeGameMode, availableGameModes, new int[]{}, true, true, new ArrayMap<>());
163     }
164 
GameModeInfo(@ameManager.GameMode int activeGameMode, @NonNull @GameManager.GameMode int[] availableGameModes, @NonNull @GameManager.GameMode int[] overriddenGameModes, boolean isDownscalingAllowed, boolean isFpsOverrideAllowed, @NonNull Map<Integer, GameModeConfiguration> configMap)165     private GameModeInfo(@GameManager.GameMode int activeGameMode,
166             @NonNull @GameManager.GameMode int[] availableGameModes,
167             @NonNull @GameManager.GameMode int[] overriddenGameModes, boolean isDownscalingAllowed,
168             boolean isFpsOverrideAllowed, @NonNull Map<Integer, GameModeConfiguration> configMap) {
169         mActiveGameMode = activeGameMode;
170         mAvailableGameModes = Arrays.copyOf(availableGameModes, availableGameModes.length);
171         mOverriddenGameModes = Arrays.copyOf(overriddenGameModes, overriddenGameModes.length);
172         mIsDownscalingAllowed = isDownscalingAllowed;
173         mIsFpsOverrideAllowed = isFpsOverrideAllowed;
174         mConfigMap = configMap;
175     }
176 
177     /** @hide */
178     @VisibleForTesting
GameModeInfo(Parcel in)179     public GameModeInfo(Parcel in) {
180         mActiveGameMode = in.readInt();
181         mAvailableGameModes = in.createIntArray();
182         mOverriddenGameModes = in.createIntArray();
183         mIsDownscalingAllowed = in.readBoolean();
184         mIsFpsOverrideAllowed = in.readBoolean();
185         mConfigMap = new ArrayMap<>();
186         in.readMap(mConfigMap,
187                 getClass().getClassLoader(), Integer.class, GameModeConfiguration.class);
188     }
189 
190     /**
191      * Returns the {@link GameManager.GameMode} the application is currently using.
192      */
getActiveGameMode()193     public @GameManager.GameMode int getActiveGameMode() {
194         return mActiveGameMode;
195     }
196 
197     /**
198      * Gets the collection of {@link GameManager.GameMode} that can be applied to the game.
199      * <p>
200      * Available games include all game modes that are either supported by the OEM in device
201      * config, or overridden by the game developers in game mode config XML, plus the default
202      * enabled modes for any game including {@link GameManager#GAME_MODE_STANDARD} and
203      * {@link GameManager#GAME_MODE_CUSTOM}.
204      * <p>
205      * Also see {@link GameModeInfo}.
206      */
207     @NonNull
getAvailableGameModes()208     public @GameManager.GameMode int[] getAvailableGameModes() {
209         return Arrays.copyOf(mAvailableGameModes, mAvailableGameModes.length);
210     }
211 
212     /**
213      * Gets the collection of {@link GameManager.GameMode} that are overridden by the game.
214      * <p>
215      * Also see {@link GameModeInfo}.
216      */
217     @NonNull
getOverriddenGameModes()218     public @GameManager.GameMode int[] getOverriddenGameModes() {
219         return Arrays.copyOf(mOverriddenGameModes, mOverriddenGameModes.length);
220     }
221 
222     /**
223      * Gets the current game mode configuration of a game mode.
224      * <p>
225      * The game mode can be null if it's overridden by the game itself, or not configured in device
226      * config nor set by the user as custom game mode configuration.
227      */
getGameModeConfiguration( @ameManager.GameMode int gameMode)228     public @Nullable GameModeConfiguration getGameModeConfiguration(
229             @GameManager.GameMode int gameMode) {
230         return mConfigMap.get(gameMode);
231     }
232 
233     /**
234      * Returns if downscaling is allowed (not opted out) by the game in their Game Mode config.
235      * <p>
236      * Also see {@link GameModeInfo}.
237      */
isDownscalingAllowed()238     public boolean isDownscalingAllowed() {
239         return mIsDownscalingAllowed;
240     }
241 
242     /**
243      * Returns if FPS override is allowed (not opted out) by the game in their Game Mode config.
244      * <p>
245      * Also see {@link GameModeInfo}.
246      */
isFpsOverrideAllowed()247     public boolean isFpsOverrideAllowed() {
248         return mIsFpsOverrideAllowed;
249     }
250 
251 
252     private final @GameManager.GameMode int[] mAvailableGameModes;
253     private final @GameManager.GameMode int[] mOverriddenGameModes;
254     private final @GameManager.GameMode int mActiveGameMode;
255     private final boolean mIsDownscalingAllowed;
256     private final boolean mIsFpsOverrideAllowed;
257     private final Map<Integer, GameModeConfiguration> mConfigMap;
258 
259     @Override
describeContents()260     public int describeContents() {
261         return 0;
262     }
263 
264     @Override
writeToParcel(@onNull Parcel dest, int flags)265     public void writeToParcel(@NonNull Parcel dest, int flags) {
266         dest.writeInt(mActiveGameMode);
267         dest.writeIntArray(mAvailableGameModes);
268         dest.writeIntArray(mOverriddenGameModes);
269         dest.writeBoolean(mIsDownscalingAllowed);
270         dest.writeBoolean(mIsFpsOverrideAllowed);
271         dest.writeMap(mConfigMap);
272     }
273 }
274