1 /*
2  * Copyright (C) 2020 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 import android.content.Context;
20 import android.hardware.display.DisplayManager;
21 import android.provider.Settings;
22 import android.util.Log;
23 import android.view.Display;
24 
25 import androidx.annotation.VisibleForTesting;
26 import androidx.preference.Preference;
27 import androidx.preference.PreferenceScreen;
28 import androidx.preference.SwitchPreference;
29 
30 import com.android.settings.R;
31 import com.android.settings.core.PreferenceControllerMixin;
32 import com.android.settingslib.development.DeveloperOptionsPreferenceController;
33 
34 public class ForcePeakRefreshRatePreferenceController extends DeveloperOptionsPreferenceController
35         implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
36 
37     @VisibleForTesting
38     static float DEFAULT_REFRESH_RATE = 60f;
39 
40     @VisibleForTesting
41     static float NO_CONFIG = 0f;
42 
43     @VisibleForTesting
44     float mPeakRefreshRate;
45 
46     private static final String TAG = "ForcePeakRefreshRateCtr";
47     private static final String PREFERENCE_KEY = "pref_key_peak_refresh_rate";
48 
ForcePeakRefreshRatePreferenceController(Context context)49     public ForcePeakRefreshRatePreferenceController(Context context) {
50         super(context);
51 
52         final DisplayManager dm = context.getSystemService(DisplayManager.class);
53         final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
54 
55         if (display == null) {
56             Log.w(TAG, "No valid default display device");
57             mPeakRefreshRate = DEFAULT_REFRESH_RATE;
58         } else {
59             mPeakRefreshRate = findPeakRefreshRate(display.getSupportedModes());
60         }
61 
62         Log.d(TAG, "DEFAULT_REFRESH_RATE : " + DEFAULT_REFRESH_RATE
63             + " mPeakRefreshRate : " + mPeakRefreshRate);
64     }
65 
66     @Override
getPreferenceKey()67     public String getPreferenceKey() {
68         return PREFERENCE_KEY;
69     }
70 
71     @Override
displayPreference(PreferenceScreen screen)72     public void displayPreference(PreferenceScreen screen) {
73         super.displayPreference(screen);
74         mPreference = screen.findPreference(getPreferenceKey());
75     }
76 
77     @Override
onPreferenceChange(Preference preference, Object newValue)78     public boolean onPreferenceChange(Preference preference, Object newValue) {
79         final boolean isEnabled = (Boolean) newValue;
80         forcePeakRefreshRate(isEnabled);
81 
82         return true;
83     }
84 
85     @Override
updateState(Preference preference)86     public void updateState(Preference preference) {
87         ((SwitchPreference) mPreference).setChecked(isForcePeakRefreshRateEnabled());
88     }
89 
90     @Override
isAvailable()91     public boolean isAvailable() {
92         if (mContext.getResources().getBoolean(R.bool.config_show_smooth_display)) {
93             return mPeakRefreshRate > DEFAULT_REFRESH_RATE;
94         } else {
95             return false;
96         }
97     }
98 
99     @Override
onDeveloperOptionsSwitchDisabled()100     protected void onDeveloperOptionsSwitchDisabled() {
101         super.onDeveloperOptionsSwitchDisabled();
102         Settings.System.putFloat(mContext.getContentResolver(),
103             Settings.System.MIN_REFRESH_RATE, NO_CONFIG);
104 
105         ((SwitchPreference) mPreference).setChecked(false);
106     }
107 
108     @VisibleForTesting
forcePeakRefreshRate(boolean enable)109     void forcePeakRefreshRate(boolean enable) {
110         final float peakRefreshRate = enable ? mPeakRefreshRate : NO_CONFIG;
111         Settings.System.putFloat(mContext.getContentResolver(),
112             Settings.System.MIN_REFRESH_RATE, peakRefreshRate);
113     }
114 
isForcePeakRefreshRateEnabled()115     boolean isForcePeakRefreshRateEnabled() {
116         final float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(),
117             Settings.System.MIN_REFRESH_RATE, NO_CONFIG);
118 
119         return peakRefreshRate >= mPeakRefreshRate;
120     }
121 
findPeakRefreshRate(Display.Mode[] modes)122     private float findPeakRefreshRate(Display.Mode[] modes) {
123         float peakRefreshRate = DEFAULT_REFRESH_RATE;
124         for (Display.Mode mode : modes) {
125             if (Math.round(mode.getRefreshRate()) > peakRefreshRate) {
126                 peakRefreshRate = mode.getRefreshRate();
127             }
128         }
129 
130         return peakRefreshRate;
131     }
132 }
133