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 int defaultPeakRefreshRate = Math.round(mPeakRefreshRate); 92 93 mPreference = screen.findPreference(getPreferenceKey()); 94 mPreference.setSummary(mContext.getString( 95 R.string.peak_refresh_rate_summary, defaultPeakRefreshRate)); 96 } 97 98 @Override getAvailabilityStatus()99 public int getAvailabilityStatus() { 100 if (mContext.getResources().getBoolean(R.bool.config_show_smooth_display)) { 101 return mPeakRefreshRate > DEFAULT_REFRESH_RATE ? AVAILABLE : UNSUPPORTED_ON_DEVICE; 102 } else { 103 return UNSUPPORTED_ON_DEVICE; 104 } 105 } 106 107 @Override isChecked()108 public boolean isChecked() { 109 final float peakRefreshRate = 110 Settings.System.getFloat( 111 mContext.getContentResolver(), 112 Settings.System.PEAK_REFRESH_RATE, 113 getDefaultPeakRefreshRate()); 114 return Math.round(peakRefreshRate) == Math.round(mPeakRefreshRate); 115 } 116 117 @Override setChecked(boolean isChecked)118 public boolean setChecked(boolean isChecked) { 119 final float peakRefreshRate = isChecked ? mPeakRefreshRate : DEFAULT_REFRESH_RATE; 120 Log.d(TAG, "setChecked to : " + peakRefreshRate); 121 122 return Settings.System.putFloat( 123 mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE, peakRefreshRate); 124 } 125 126 @Override getSliceHighlightMenuRes()127 public int getSliceHighlightMenuRes() { 128 return R.string.menu_key_display; 129 } 130 131 @Override onStart()132 public void onStart() { 133 mDeviceConfigDisplaySettings.startListening(); 134 } 135 136 @Override onStop()137 public void onStop() { 138 mDeviceConfigDisplaySettings.stopListening(); 139 } 140 141 @VisibleForTesting findPeakRefreshRate(Display.Mode[] modes)142 float findPeakRefreshRate(Display.Mode[] modes) { 143 float peakRefreshRate = DEFAULT_REFRESH_RATE; 144 for (Display.Mode mode : modes) { 145 if (Math.round(mode.getRefreshRate()) > peakRefreshRate) { 146 peakRefreshRate = mode.getRefreshRate(); 147 } 148 } 149 return peakRefreshRate; 150 } 151 152 private class DeviceConfigDisplaySettings 153 implements DeviceConfig.OnPropertiesChangedListener, Executor { startListening()154 public void startListening() { 155 DeviceConfig.addOnPropertiesChangedListener( 156 DeviceConfig.NAMESPACE_DISPLAY_MANAGER, 157 this /* Executor */, 158 this /* Listener */); 159 } 160 stopListening()161 public void stopListening() { 162 DeviceConfig.removeOnPropertiesChangedListener(this); 163 } 164 getDefaultPeakRefreshRate()165 public float getDefaultPeakRefreshRate() { 166 float defaultPeakRefreshRate = 167 DeviceConfig.getFloat( 168 DeviceConfig.NAMESPACE_DISPLAY_MANAGER, 169 DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, 170 INVALIDATE_REFRESH_RATE); 171 Log.d(TAG, "DeviceConfig getDefaultPeakRefreshRate : " + defaultPeakRefreshRate); 172 173 return defaultPeakRefreshRate; 174 } 175 176 @Override onPropertiesChanged(DeviceConfig.Properties properties)177 public void onPropertiesChanged(DeviceConfig.Properties properties) { 178 // Got notified if any property has been changed in NAMESPACE_DISPLAY_MANAGER. The 179 // KEY_PEAK_REFRESH_RATE_DEFAULT value could be added, changed, removed or unchanged. 180 // Just force a UI update for any case. 181 if (mOnDeviceConfigChange != null) { 182 mOnDeviceConfigChange.onDefaultRefreshRateChanged(); 183 updateState(mPreference); 184 } 185 } 186 187 @Override execute(Runnable runnable)188 public void execute(Runnable runnable) { 189 if (mHandler != null) { 190 mHandler.post(runnable); 191 } 192 } 193 } 194 getDefaultPeakRefreshRate()195 private float getDefaultPeakRefreshRate() { 196 float defaultPeakRefreshRate = mDeviceConfigDisplaySettings.getDefaultPeakRefreshRate(); 197 if (defaultPeakRefreshRate == INVALIDATE_REFRESH_RATE) { 198 defaultPeakRefreshRate = (float) mContext.getResources().getInteger( 199 com.android.internal.R.integer.config_defaultPeakRefreshRate); 200 } 201 202 Log.d(TAG, "DeviceConfig getDefaultPeakRefreshRate : " + defaultPeakRefreshRate); 203 return defaultPeakRefreshRate; 204 } 205 } 206