1 /*
2  * Copyright (C) 2023 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 com.android.settings.development;
18 
19 
20 import android.app.IGameManagerService;
21 import android.content.Context;
22 import android.os.RemoteException;
23 import android.os.ServiceManager;
24 import android.os.SystemProperties;
25 
26 import androidx.annotation.VisibleForTesting;
27 import androidx.preference.Preference;
28 import androidx.preference.TwoStatePreference;
29 
30 import com.android.settings.R;
31 import com.android.settings.core.PreferenceControllerMixin;
32 import com.android.settings.flags.Flags;
33 import com.android.settingslib.development.DeveloperOptionsPreferenceController;
34 
35 public class GameDefaultFrameRatePreferenceController extends DeveloperOptionsPreferenceController
36         implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin  {
37     private static final String TAG = "GameDefFrameRatePrefCtr";
38     private static final String DISABLE_GAME_DEFAULT_FRAME_RATE_KEY =
39             "disable_game_default_frame_rate";
40     private final IGameManagerService mGameManagerService;
41     static final String PROPERTY_DEBUG_GFX_GAME_DEFAULT_FRAME_RATE_DISABLED =
42             "debug.graphics.game_default_frame_rate.disabled";
43 
44     private final DevelopmentSystemPropertiesWrapper mSysProps;
45     private int mGameDefaultFrameRateValue;
46 
47     @VisibleForTesting
48     static class Injector {
createSystemPropertiesWrapper()49         public DevelopmentSystemPropertiesWrapper createSystemPropertiesWrapper() {
50             return new DevelopmentSystemPropertiesWrapper() {
51                 @Override
52                 public String get(String key, String def) {
53                     return SystemProperties.get(key, def);
54                 }
55                 @Override
56                 public boolean getBoolean(String key, boolean def) {
57                     return SystemProperties.getBoolean(key, def);
58                 }
59 
60                 @Override
61                 public int getInt(String key, int def) {
62                     return SystemProperties.getInt(key, def);
63                 }
64 
65                 @Override
66                 public void set(String key, String val) {
67                     SystemProperties.set(key, val);
68                 }
69             };
70         }
71     }
72 
73     public GameDefaultFrameRatePreferenceController(Context context) {
74         super(context);
75         mGameManagerService = IGameManagerService.Stub.asInterface(
76                 ServiceManager.getService(Context.GAME_SERVICE));
77 
78         mSysProps = new Injector().createSystemPropertiesWrapper();
79 
80         mGameDefaultFrameRateValue = mSysProps.getInt(
81                 "ro.surface_flinger.game_default_frame_rate_override", 60);
82     }
83 
84     @VisibleForTesting
85     GameDefaultFrameRatePreferenceController(Context context,
86                                              IGameManagerService gameManagerService,
87                                              Injector injector) {
88         super(context);
89         mGameManagerService = gameManagerService;
90         mSysProps = injector.createSystemPropertiesWrapper();
91     }
92 
93     @Override
94     public String getPreferenceKey() {
95         return DISABLE_GAME_DEFAULT_FRAME_RATE_KEY;
96     }
97 
98     @Override
99     public boolean onPreferenceChange(Preference preference, Object newValue) {
100         final boolean isDisabled = (Boolean) newValue;
101         try {
102             mGameManagerService.toggleGameDefaultFrameRate(!isDisabled);
103             updateGameDefaultPreferenceSetting();
104         } catch (RemoteException e) {
105             // intentional no-op
106         }
107         return true;
108     }
109 
110     private void updateGameDefaultPreferenceSetting() {
111         final boolean isDisabled =
112                 mSysProps.getBoolean(PROPERTY_DEBUG_GFX_GAME_DEFAULT_FRAME_RATE_DISABLED,
113                         false);
114         ((TwoStatePreference) mPreference).setChecked(isDisabled);
115         mPreference.setSummary(mContext.getString(
116                 R.string.disable_game_default_frame_rate_summary,
117                 mGameDefaultFrameRateValue));
118     }
119     @Override
120     public void updateState(Preference preference) {
121         super.updateState(preference);
122         updateGameDefaultPreferenceSetting();
123     }
124 
125     @Override
126     public boolean isAvailable() {
127         return Flags.developmentGameDefaultFrameRate();
128     }
129 
130     @Override
131     protected void onDeveloperOptionsSwitchDisabled() {
132         super.onDeveloperOptionsSwitchDisabled();
133         final TwoStatePreference preference = (TwoStatePreference) mPreference;
134         if (preference.isChecked()) {
135             // When the developer option is disabled, we should set everything
136             // to off, that is, enabling game default frame rate.
137             try {
138                 mGameManagerService.toggleGameDefaultFrameRate(true);
139             } catch (RemoteException e) {
140                 // intentional no-op
141             }
142         }
143         preference.setChecked(false);
144     }
145 
146 }
147