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