Migrate Smooth display

Test: manual test
Bug: 374936314
Bug: 368359268
Flag: com.android.settings.flags.catalyst_display_settings_screen
Change-Id: Iaacf72751806ca64018145531dd33d510dca7f6a
diff --git a/src/com/android/settings/display/DisplayScreen.kt b/src/com/android/settings/display/DisplayScreen.kt
index 6c7630b..bd21e8e 100644
--- a/src/com/android/settings/display/DisplayScreen.kt
+++ b/src/com/android/settings/display/DisplayScreen.kt
@@ -49,6 +49,7 @@
 
     override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {
         +DarkModeScreen.KEY
+        +PeakRefreshRateSwitchPreference()
     }
 
     override fun isAvailable(context: Context) =
diff --git a/src/com/android/settings/display/PeakRefreshRatePreferenceController.java b/src/com/android/settings/display/PeakRefreshRatePreferenceController.java
index 261eaf1..740a726 100644
--- a/src/com/android/settings/display/PeakRefreshRatePreferenceController.java
+++ b/src/com/android/settings/display/PeakRefreshRatePreferenceController.java
@@ -40,6 +40,7 @@
 
 import java.util.concurrent.Executor;
 
+// LINT.IfChange
 public class PeakRefreshRatePreferenceController extends TogglePreferenceController
         implements LifecycleObserver, OnStart, OnStop {
 
@@ -196,3 +197,4 @@
         return defaultPeakRefreshRate;
     }
 }
+// LINT.ThenChange(PeakRefreshRateSwitchPreference.kt)
diff --git a/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt b/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt
new file mode 100644
index 0000000..793b0e2
--- /dev/null
+++ b/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.display
+
+import android.content.Context
+import android.hardware.display.DisplayManager
+import android.provider.DeviceConfig
+import android.util.Log
+import com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE
+import com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateAmongAllDisplays
+import com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay
+import com.android.server.display.feature.flags.Flags
+import com.android.settings.R
+import com.android.settingslib.datastore.HandlerExecutor
+import com.android.settingslib.datastore.SettingsSystemStore
+import com.android.settingslib.metadata.PreferenceAvailabilityProvider
+import com.android.settingslib.metadata.PreferenceLifecycleContext
+import com.android.settingslib.metadata.PreferenceLifecycleProvider
+import com.android.settingslib.metadata.PreferenceSummaryProvider
+import com.android.settingslib.metadata.SwitchPreference
+import com.android.settingslib.preference.SwitchPreferenceBinding
+import kotlin.math.roundToInt
+
+// LINT.IfChange
+class PeakRefreshRateSwitchPreference :
+    SwitchPreference("peak_refresh_rate", R.string.peak_refresh_rate_title),
+    SwitchPreferenceBinding,
+    PreferenceAvailabilityProvider,
+    PreferenceSummaryProvider,
+    PreferenceLifecycleProvider {
+
+    private var propertiesChangedListener: DeviceConfig.OnPropertiesChangedListener? = null
+
+    override fun storage(context: Context) = SettingsSystemStore.get(context)
+
+    override fun isAvailable(context: Context) =
+        context.resources.getBoolean(R.bool.config_show_smooth_display) &&
+            (getPeakRefreshRate(context) > DEFAULT_REFRESH_RATE)
+
+    override fun getSummary(context: Context) =
+        context.getString(
+            R.string.peak_refresh_rate_summary,
+            getPeakRefreshRate(context).roundToInt(),
+        )
+
+    override fun onStart(context: PreferenceLifecycleContext) {
+        val listener =
+            object : DeviceConfig.OnPropertiesChangedListener {
+                // Got notified if any property has been changed in NAMESPACE_DISPLAY_MANAGER. The
+                // KEY_PEAK_REFRESH_RATE_DEFAULT value could be added, changed, removed or
+                // unchanged.
+                // Just force a UI update for any case.
+                override fun onPropertiesChanged(properties: DeviceConfig.Properties) =
+                    context.notifyPreferenceChange(this@PeakRefreshRateSwitchPreference)
+            }
+
+        propertiesChangedListener = listener
+
+        DeviceConfig.addOnPropertiesChangedListener(
+            DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+            HandlerExecutor.main,
+            listener,
+        )
+    }
+
+    override fun onStop(context: PreferenceLifecycleContext) {
+        propertiesChangedListener?.let {
+            DeviceConfig.removeOnPropertiesChangedListener(it)
+            propertiesChangedListener = null
+        }
+    }
+
+    private fun getPeakRefreshRate(context: Context): Float =
+        Math.round(
+                when {
+                    Flags.backUpSmoothDisplayAndForcePeakRefreshRate() ->
+                        findHighestRefreshRateAmongAllDisplays(context)
+                    else -> findHighestRefreshRateForDefaultDisplay(context)
+                }
+            )
+            .toFloat()
+
+    private fun getDefaultPeakRefreshRate(context: Context): Float {
+        var defaultPeakRefreshRate =
+            DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT,
+                INVALIDATE_REFRESH_RATE,
+            )
+
+        if (defaultPeakRefreshRate == INVALIDATE_REFRESH_RATE) {
+            defaultPeakRefreshRate =
+                context.resources
+                    .getInteger(com.android.internal.R.integer.config_defaultPeakRefreshRate)
+                    .toFloat()
+        }
+
+        Log.d(TAG, "DeviceConfig getDefaultPeakRefreshRate : $defaultPeakRefreshRate")
+        return defaultPeakRefreshRate
+    }
+
+    companion object {
+        private const val TAG: String = "PeakRefreshRateSwitchPreference"
+        private const val INVALIDATE_REFRESH_RATE: Float = -1f
+    }
+}
+// LINT.ThenChange(PeakRefreshRatePreferenceController.java)