diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index cc6bafb2562..c81d504b223 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -311,6 +311,11 @@ public class SettingsActivity extends SettingsBaseActivity } setContentView(R.layout.settings_main_prefs); + mMainSwitch = findViewById(R.id.switch_bar); + if (mMainSwitch != null) { + mMainSwitch.setMetricsCategory(lookupMetricsCategory()); + mMainSwitch.setTranslationZ(findViewById(R.id.main_content).getTranslationZ() + 1); + } getSupportFragmentManager().addOnBackStackChangedListener(this); @@ -330,12 +335,6 @@ public class SettingsActivity extends SettingsBaseActivity launchSettingFragment(initialFragmentName, intent); } - mMainSwitch = findViewById(R.id.switch_bar); - if (mMainSwitch != null) { - mMainSwitch.setMetricsCategory(lookupMetricsCategory()); - mMainSwitch.setTranslationZ(findViewById(R.id.main_content).getTranslationZ() + 1); - } - // see if we should show Back/Next buttons if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) { diff --git a/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt b/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt new file mode 100644 index 00000000000..b05cbc88d9f --- /dev/null +++ b/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt @@ -0,0 +1,71 @@ +/* + * 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.datausage + +import android.content.Context +import com.android.settings.R +import com.android.settings.widget.MainSwitchBarMetadata +import com.android.settingslib.datastore.KeyValueStore +import com.android.settingslib.datastore.NoOpKeyedObservable +import com.android.settingslib.metadata.PreferenceLifecycleContext +import com.android.settingslib.metadata.PreferenceLifecycleProvider +import com.android.settingslib.metadata.ReadWritePermit + +class DataSaverMainSwitchPreference(context: Context) : + MainSwitchBarMetadata, PreferenceLifecycleProvider { + + private val dataSaverBackend = DataSaverBackend(context) + private var dataSaverBackendListener: DataSaverBackend.Listener? = null + + override val key + get() = "use_data_saver" + + override val title + get() = R.string.data_saver_switch_title + + override fun storage(context: Context): KeyValueStore = DataSaverStore(dataSaverBackend) + + override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) = + ReadWritePermit.ALLOW + + override fun onStart(context: PreferenceLifecycleContext) { + val listener = DataSaverBackend.Listener { context.notifyPreferenceChange(this) } + dataSaverBackendListener = listener + dataSaverBackend.addListener(listener) + } + + override fun onStop(context: PreferenceLifecycleContext) { + dataSaverBackendListener?.let { + dataSaverBackend.remListener(it) + dataSaverBackendListener = null + } + } + + @Suppress("UNCHECKED_CAST") + private class DataSaverStore(private val dataSaverBackend: DataSaverBackend) : + NoOpKeyedObservable(), KeyValueStore { + + override fun contains(key: String) = true // just assume the datastore contains the value + + override fun getValue(key: String, valueType: Class): T? = + dataSaverBackend.isDataSaverEnabled as T? + + override fun setValue(key: String, valueType: Class, value: T?) { + dataSaverBackend.isDataSaverEnabled = value as Boolean + } + } +} diff --git a/src/com/android/settings/datausage/DataSaverScreen.kt b/src/com/android/settings/datausage/DataSaverScreen.kt index eafaa1e8c03..9a9b79018a1 100644 --- a/src/com/android/settings/datausage/DataSaverScreen.kt +++ b/src/com/android/settings/datausage/DataSaverScreen.kt @@ -38,7 +38,8 @@ class DataSaverScreen : PreferenceScreenCreator { override fun fragmentClass() = DataSaverSummary::class.java - override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {} + override fun getPreferenceHierarchy(context: Context) = + preferenceHierarchy(this) { +DataSaverMainSwitchPreference(context) } override fun hasCompleteHierarchy() = false diff --git a/src/com/android/settings/datausage/DataSaverSummary.kt b/src/com/android/settings/datausage/DataSaverSummary.kt index 8db633331bc..60de8a72539 100644 --- a/src/com/android/settings/datausage/DataSaverSummary.kt +++ b/src/com/android/settings/datausage/DataSaverSummary.kt @@ -43,26 +43,34 @@ class DataSaverSummary : DashboardFragment() { return } - dataSaverBackend = DataSaverBackend(requireContext()) + if (!isCatalystEnabled) { + dataSaverBackend = DataSaverBackend(requireContext()) + } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - switchBar = (activity as SettingsActivity).switchBar.apply { - setTitle(getString(R.string.data_saver_switch_title)) - show() - addOnSwitchChangeListener { _, isChecked -> onSwitchChanged(isChecked) } + if (!isCatalystEnabled) { + switchBar = (activity as SettingsActivity).switchBar.apply { + setTitle(getString(R.string.data_saver_switch_title)) + show() + addOnSwitchChangeListener { _, isChecked -> onSwitchChanged(isChecked) } + } } } override fun onResume() { super.onResume() - dataSaverBackend.addListener(dataSaverBackendListener) + if (!isCatalystEnabled) { + dataSaverBackend.addListener(dataSaverBackendListener) + } } override fun onPause() { super.onPause() - dataSaverBackend.remListener(dataSaverBackendListener) + if (!isCatalystEnabled) { + dataSaverBackend.remListener(dataSaverBackendListener) + } } private fun onSwitchChanged(isChecked: Boolean) { diff --git a/src/com/android/settings/widget/MainSwitchBarMetadata.kt b/src/com/android/settings/widget/MainSwitchBarMetadata.kt new file mode 100644 index 00000000000..f55cfd03789 --- /dev/null +++ b/src/com/android/settings/widget/MainSwitchBarMetadata.kt @@ -0,0 +1,36 @@ +/* + * 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.widget + +import android.content.Context +import androidx.preference.Preference +import com.android.settingslib.metadata.PreferenceMetadata +import com.android.settingslib.metadata.TwoStatePreference +import com.android.settingslib.preference.PreferenceBindingPlaceholder +import com.android.settingslib.preference.TwoStatePreferenceBinding + +/** Base metadata of `MainSwitchBar`. */ +interface MainSwitchBarMetadata : + TwoStatePreference, TwoStatePreferenceBinding, PreferenceBindingPlaceholder { + + override fun createWidget(context: Context) = MainSwitchBarPreference(context, this) + + override fun bind(preference: Preference, metadata: PreferenceMetadata) { + super.bind(preference, metadata) + (preference as MainSwitchBarPreference).updateVisibility() + } +} diff --git a/src/com/android/settings/widget/MainSwitchBarPreference.kt b/src/com/android/settings/widget/MainSwitchBarPreference.kt new file mode 100644 index 00000000000..6ed887790c8 --- /dev/null +++ b/src/com/android/settings/widget/MainSwitchBarPreference.kt @@ -0,0 +1,79 @@ +/* + * 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.widget + +import android.content.Context +import android.widget.CompoundButton +import android.widget.CompoundButton.OnCheckedChangeListener +import androidx.preference.TwoStatePreference +import com.android.settings.SettingsActivity +import com.android.settingslib.metadata.PreferenceAvailabilityProvider +import com.android.settingslib.widget.MainSwitchBar + +/** Preference abstraction of the [MainSwitchBar] in settings activity. */ +class MainSwitchBarPreference(context: Context, private val metadata: MainSwitchBarMetadata) : + TwoStatePreference(context), OnCheckedChangeListener { + + private val mainSwitchBar: MainSwitchBar = (context as SettingsActivity).switchBar + + override fun setTitle(title: CharSequence?) { + mainSwitchBar.setTitle(title) + } + + override fun setSummary(summary: CharSequence?) { + mainSwitchBar.setSummary(summary) + } + + override fun setEnabled(enabled: Boolean) { + mainSwitchBar.isEnabled = enabled + } + + // Preference.setVisible is final, we cannot override it + fun updateVisibility() { + // always make preference invisible, the UI visibility is reflected on MainSwitchBar + isVisible = false + if ((metadata as? PreferenceAvailabilityProvider)?.isAvailable(context) != false) { + mainSwitchBar.show() + } else { + mainSwitchBar.hide() + } + } + + override fun setChecked(checked: Boolean) { + // remove listener to update UI only + mainSwitchBar.removeOnSwitchChangeListener(this) + mainSwitchBar.isChecked = checked + mainSwitchBar.addOnSwitchChangeListener(this) + } + + override fun onAttached() { + super.onAttached() + mainSwitchBar.addOnSwitchChangeListener(this) + } + + override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) { + // prevent user from toggling the switch before data store operation is done + isEnabled = false + // once data store is updated, isEnabled will be reset due to rebind + persistBoolean(isChecked) + } + + override fun onDetached() { + mainSwitchBar.removeOnSwitchChangeListener(this) + super.onDetached() + } +}