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.display; 18 19 import android.content.Context; 20 import android.hardware.display.DisplayManager; 21 import android.os.Handler; 22 import android.provider.DeviceConfig; 23 import android.provider.Settings; 24 import android.util.Log; 25 import android.view.Display; 26 27 import androidx.annotation.VisibleForTesting; 28 import androidx.preference.Preference; 29 import androidx.preference.PreferenceScreen; 30 31 import com.android.settings.R; 32 import com.android.settings.core.TogglePreferenceController; 33 import com.android.settingslib.core.lifecycle.LifecycleObserver; 34 import com.android.settingslib.core.lifecycle.events.OnStart; 35 import com.android.settingslib.core.lifecycle.events.OnStop; 36 37 import java.util.concurrent.Executor; 38 39 public class PeakRefreshRatePreferenceController extends TogglePreferenceController 40 implements LifecycleObserver, OnStart, OnStop { 41 42 @VisibleForTesting static float DEFAULT_REFRESH_RATE = 60f; 43 44 @VisibleForTesting float mPeakRefreshRate; 45 46 private static final String TAG = "RefreshRatePrefCtr"; 47 private static final float INVALIDATE_REFRESH_RATE = -1f; 48 49 private final Handler mHandler; 50 private final IDeviceConfigChange mOnDeviceConfigChange; 51 private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; 52 private Preference mPreference; 53 54 private interface IDeviceConfigChange { onDefaultRefreshRateChanged()55 void onDefaultRefreshRateChanged(); 56 } 57 PeakRefreshRatePreferenceController(Context context, String key)58 public PeakRefreshRatePreferenceController(Context context, String key) { 59 super(context, key); 60 mHandler = new Handler(context.getMainLooper()); 61 mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); 62 mOnDeviceConfigChange = 63 new IDeviceConfigChange() { 64 public void onDefaultRefreshRateChanged() { 65 updateState(mPreference); 66 } 67 }; 68 69 final DisplayManager dm = mContext.getSystemService(DisplayManager.class); 70 final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY); 71 72 if (display == null) { 73 Log.w(TAG, "No valid default display device"); 74 mPeakRefreshRate = DEFAULT_REFRESH_RATE; 75 } else { 76 mPeakRefreshRate = findPeakRefreshRate(display.getSupportedModes()); 77 } 78 79 Log.d( 80 TAG, 81 "DEFAULT_REFRESH_RATE : " 82 + DEFAULT_REFRESH_RATE 83 + " mPeakRefreshRate : " 84 + mPeakRefreshRate); 85 } 86 87 @Override displayPreference(PreferenceScreen screen)88 public void displayPreference(PreferenceScreen screen) { 89 super.displayPreference(screen); 90 91 mPreference = screen.findPreference(getPreferenceKey()); 92 } 93 94 @Override getAvailabilityStatus()95 public int getAvailabilityStatus() { 96 if (mContext.getResources().getBoolean(R.bool.config_show_smooth_display)) { 97 return mPeakRefreshRate > DEFAULT_REFRESH_RATE ? AVAILABLE : UNSUPPORTED_ON_DEVICE; 98 } else { 99 return UNSUPPORTED_ON_DEVICE; 100 } 101 } 102 103 @Override isChecked()104 public boolean isChecked() { 105 final float peakRefreshRate = 106 Settings.System.getFloat( 107 mContext.getContentResolver(), 108 Settings.System.PEAK_REFRESH_RATE, 109 getDefaultPeakRefreshRate()); 110 return Math.round(peakRefreshRate) == Math.round(mPeakRefreshRate); 111 } 112 113 @Override setChecked(boolean isChecked)114 public boolean setChecked(boolean isChecked) { 115 final float peakRefreshRate = isChecked ? mPeakRefreshRate : DEFAULT_REFRESH_RATE; 116 Log.d(TAG, "setChecked to : " + peakRefreshRate); 117 118 return Settings.System.putFloat( 119 mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE, peakRefreshRate); 120 } 121 122 @Override getSliceHighlightMenuRes()123 public int getSliceHighlightMenuRes() { 124 return R.string.menu_key_display; 125 } 126 127 @Override onStart()128 public void onStart() { 129 mDeviceConfigDisplaySettings.startListening(); 130 } 131 132 @Override onStop()133 public void onStop() { 134 mDeviceConfigDisplaySettings.stopListening(); 135 } 136 137 @VisibleForTesting findPeakRefreshRate(Display.Mode[] modes)138 float findPeakRefreshRate(Display.Mode[] modes) { 139 float peakRefreshRate = DEFAULT_REFRESH_RATE; 140 for (Display.Mode mode : modes) { 141 if (Math.round(mode.getRefreshRate()) > peakRefreshRate) { 142 peakRefreshRate = mode.getRefreshRate(); 143 } 144 } 145 return peakRefreshRate; 146 } 147 148 private class DeviceConfigDisplaySettings 149 implements DeviceConfig.OnPropertiesChangedListener, Executor { startListening()150 public void startListening() { 151 DeviceConfig.addOnPropertiesChangedListener( 152 DeviceConfig.NAMESPACE_DISPLAY_MANAGER, 153 this /* Executor */, 154 this /* Listener */); 155 } 156 stopListening()157 public void stopListening() { 158 DeviceConfig.removeOnPropertiesChangedListener(this); 159 } 160 getDefaultPeakRefreshRate()161 public float getDefaultPeakRefreshRate() { 162 float defaultPeakRefreshRate = 163 DeviceConfig.getFloat( 164 DeviceConfig.NAMESPACE_DISPLAY_MANAGER, 165 DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, 166 INVALIDATE_REFRESH_RATE); 167 Log.d(TAG, "DeviceConfig getDefaultPeakRefreshRate : " + defaultPeakRefreshRate); 168 169 return defaultPeakRefreshRate; 170 } 171 172 @Override onPropertiesChanged(DeviceConfig.Properties properties)173 public void onPropertiesChanged(DeviceConfig.Properties properties) { 174 // Got notified if any property has been changed in NAMESPACE_DISPLAY_MANAGER. The 175 // KEY_PEAK_REFRESH_RATE_DEFAULT value could be added, changed, removed or unchanged. 176 // Just force a UI update for any case. 177 if (mOnDeviceConfigChange != null) { 178 mOnDeviceConfigChange.onDefaultRefreshRateChanged(); 179 updateState(mPreference); 180 } 181 } 182 183 @Override execute(Runnable runnable)184 public void execute(Runnable runnable) { 185 if (mHandler != null) { 186 mHandler.post(runnable); 187 } 188 } 189 } 190 getDefaultPeakRefreshRate()191 private float getDefaultPeakRefreshRate() { 192 float defaultPeakRefreshRate = mDeviceConfigDisplaySettings.getDefaultPeakRefreshRate(); 193 if (defaultPeakRefreshRate == INVALIDATE_REFRESH_RATE) { 194 defaultPeakRefreshRate = (float) mContext.getResources().getInteger( 195 com.android.internal.R.integer.config_defaultPeakRefreshRate); 196 } 197 198 Log.d(TAG, "DeviceConfig getDefaultPeakRefreshRate : " + defaultPeakRefreshRate); 199 return defaultPeakRefreshRate; 200 } 201 } 202