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