diff --git a/src/com/android/settings/PreferenceRestrictionMixin.kt b/src/com/android/settings/PreferenceRestrictionMixin.kt new file mode 100644 index 00000000000..c70b94bf500 --- /dev/null +++ b/src/com/android/settings/PreferenceRestrictionMixin.kt @@ -0,0 +1,44 @@ +/* + * 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 + +import android.content.Context +import android.os.UserHandle +import androidx.annotation.CallSuper +import com.android.settingslib.RestrictedLockUtilsInternal +import com.android.settingslib.metadata.PreferenceRestrictionProvider + +/** Mixin to support restriction. */ +interface PreferenceRestrictionMixin : PreferenceRestrictionProvider { + + val restrictionKey: String + + val useAdminDisabledSummary: Boolean + get() = false + + @CallSuper fun isEnabled(context: Context) = !context.hasBaseUserRestriction(restrictionKey) + + override fun isRestricted(context: Context) = + RestrictedLockUtilsInternal.checkIfRestrictionEnforced( + context, + restrictionKey, + UserHandle.myUserId(), + ) != null +} + +fun Context.hasBaseUserRestriction(restrictionKey: String) = + RestrictedLockUtilsInternal.hasBaseUserRestriction(this, restrictionKey, UserHandle.myUserId()) diff --git a/src/com/android/settings/RestrictedListPreference.java b/src/com/android/settings/RestrictedListPreference.java index d75f1b8fae9..d5bc3418627 100644 --- a/src/com/android/settings/RestrictedListPreference.java +++ b/src/com/android/settings/RestrictedListPreference.java @@ -33,6 +33,7 @@ import android.widget.CheckedTextView; import android.widget.ListAdapter; import android.widget.ListView; +import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog.Builder; import androidx.preference.ListPreferenceDialogFragmentCompat; @@ -40,11 +41,14 @@ import androidx.preference.PreferenceViewHolder; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedPreferenceHelper; +import com.android.settingslib.RestrictedPreferenceHelperProvider; import java.util.ArrayList; import java.util.List; -public class RestrictedListPreference extends CustomListPreference { +public class RestrictedListPreference extends CustomListPreference implements + RestrictedPreferenceHelperProvider { + private final RestrictedPreferenceHelper mHelper; private final List mRestrictedItems = new ArrayList<>(); private boolean mRequiresActiveUnlockedProfile = false; @@ -61,6 +65,11 @@ public class RestrictedListPreference extends CustomListPreference { mHelper = new RestrictedPreferenceHelper(context, this, attrs); } + @Override + public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() { + return mHelper; + } + @Override public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder); diff --git a/src/com/android/settings/SettingsApplication.java b/src/com/android/settings/SettingsApplication.java index c908855ee49..99d3d922a0c 100644 --- a/src/com/android/settings/SettingsApplication.java +++ b/src/com/android/settings/SettingsApplication.java @@ -46,6 +46,7 @@ import com.android.settingslib.datastore.BackupRestoreStorageManager; import com.android.settingslib.metadata.PreferenceScreenMetadata; import com.android.settingslib.metadata.PreferenceScreenRegistry; import com.android.settingslib.metadata.ProvidePreferenceScreenOptions; +import com.android.settingslib.preference.PreferenceBindingFactory; import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory; import com.google.android.setupcompat.util.WizardManagerHelper; @@ -76,6 +77,7 @@ public class SettingsApplication extends Application { if (Flags.catalyst()) { PreferenceScreenRegistry.INSTANCE.setPreferenceScreensSupplier( this::getPreferenceScreens); + PreferenceBindingFactory.setDefaultFactory(new SettingsPreferenceBindingFactory()); } BackupRestoreStorageManager.getInstance(this) diff --git a/src/com/android/settings/SettingsPreferenceBindingFactory.kt b/src/com/android/settings/SettingsPreferenceBindingFactory.kt new file mode 100644 index 00000000000..53e5d0f45b5 --- /dev/null +++ b/src/com/android/settings/SettingsPreferenceBindingFactory.kt @@ -0,0 +1,49 @@ +/* + * 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 + +import android.os.UserHandle +import androidx.preference.Preference +import com.android.settingslib.RestrictedPreferenceHelperProvider +import com.android.settingslib.metadata.PreferenceHierarchyNode +import com.android.settingslib.preference.DefaultPreferenceBindingFactory +import com.android.settingslib.preference.PreferenceBinding + +/** Preference binding factory for settings app. */ +class SettingsPreferenceBindingFactory : DefaultPreferenceBindingFactory() { + override fun bind( + preference: Preference, + node: PreferenceHierarchyNode, + preferenceBinding: PreferenceBinding?, + ) { + super.bind(preference, node, preferenceBinding) + + // handle restriction consistently + val metadata = node.metadata + if (metadata is PreferenceRestrictionMixin) { + if (preference is RestrictedPreferenceHelperProvider) { + preference.getRestrictedPreferenceHelper().apply { + val restrictionKey = metadata.restrictionKey + if (!preference.context.hasBaseUserRestriction(restrictionKey)) { + useAdminDisabledSummary(metadata.useAdminDisabledSummary) + checkRestrictionAndSetDisabled(restrictionKey, UserHandle.myUserId()) + } + } + } + } + } +} diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccessPreference.java b/src/com/android/settings/datausage/UnrestrictedDataAccessPreference.java index b3e66a9ce06..bb84c1804e9 100644 --- a/src/com/android/settings/datausage/UnrestrictedDataAccessPreference.java +++ b/src/com/android/settings/datausage/UnrestrictedDataAccessPreference.java @@ -30,6 +30,7 @@ import com.android.settings.applications.appinfo.AppInfoDashboardFragment; import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.RestrictedPreferenceHelper; +import com.android.settingslib.RestrictedPreferenceHelperProvider; import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; @@ -37,7 +38,7 @@ import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.widget.AppSwitchPreference; public class UnrestrictedDataAccessPreference extends AppSwitchPreference implements - DataSaverBackend.Listener { + DataSaverBackend.Listener, RestrictedPreferenceHelperProvider { private static final String ECM_SETTING_IDENTIFIER = "android:unrestricted_data_access"; private final ApplicationsState mApplicationsState; @@ -78,6 +79,11 @@ public class UnrestrictedDataAccessPreference extends AppSwitchPreference implem return entry.info.packageName + "|" + entry.info.uid; } + @Override + public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() { + return mHelper; + } + @Override public void onAttached() { super.onAttached(); diff --git a/src/com/android/settings/notification/CallVolumePreference.kt b/src/com/android/settings/notification/CallVolumePreference.kt index 3c14ae4fafb..df6c4275c94 100644 --- a/src/com/android/settings/notification/CallVolumePreference.kt +++ b/src/com/android/settings/notification/CallVolumePreference.kt @@ -20,18 +20,16 @@ import android.content.Context import android.media.AudioManager import android.media.AudioManager.STREAM_BLUETOOTH_SCO import android.media.AudioManager.STREAM_VOICE_CALL -import android.os.UserHandle -import android.os.UserManager.DISALLOW_ADJUST_VOLUME +import android.os.UserManager import androidx.preference.Preference +import com.android.settings.PreferenceRestrictionMixin import com.android.settings.R -import com.android.settingslib.RestrictedLockUtilsInternal import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.datastore.NoOpKeyedObservable import com.android.settingslib.metadata.PersistentPreference import com.android.settingslib.metadata.PreferenceAvailabilityProvider import com.android.settingslib.metadata.PreferenceIconProvider import com.android.settingslib.metadata.PreferenceMetadata -import com.android.settingslib.metadata.PreferenceRestrictionProvider import com.android.settingslib.metadata.RangeValue import com.android.settingslib.metadata.ReadWritePermit import com.android.settingslib.preference.PreferenceBinding @@ -44,7 +42,7 @@ open class CallVolumePreference : RangeValue, PreferenceAvailabilityProvider, PreferenceIconProvider, - PreferenceRestrictionProvider { + PreferenceRestrictionMixin { override val key: String get() = KEY @@ -55,18 +53,12 @@ open class CallVolumePreference : override fun isAvailable(context: Context) = context.resources.getBoolean(R.bool.config_show_call_volume) && - !createAudioHelper(context).isSingleVolume() + !createAudioHelper(context).isSingleVolume - override fun isRestricted(context: Context) = - RestrictedLockUtilsInternal.hasBaseUserRestriction( - context, - DISALLOW_ADJUST_VOLUME, - UserHandle.myUserId() - ) || RestrictedLockUtilsInternal.checkIfRestrictionEnforced( - context, - DISALLOW_ADJUST_VOLUME, - UserHandle.myUserId() - ) != null + override fun isEnabled(context: Context) = super.isEnabled(context) + + override val restrictionKey: String + get() = UserManager.DISALLOW_ADJUST_VOLUME override fun storage(context: Context): KeyValueStore { val helper = createAudioHelper(context) diff --git a/src/com/android/settings/notification/MediaVolumePreference.kt b/src/com/android/settings/notification/MediaVolumePreference.kt index acb8f8d3af1..a39023361f4 100644 --- a/src/com/android/settings/notification/MediaVolumePreference.kt +++ b/src/com/android/settings/notification/MediaVolumePreference.kt @@ -18,18 +18,16 @@ package com.android.settings.notification import android.content.Context import android.media.AudioManager.STREAM_MUSIC -import android.os.UserHandle import android.os.UserManager import androidx.preference.Preference +import com.android.settings.PreferenceRestrictionMixin import com.android.settings.R -import com.android.settingslib.RestrictedLockUtilsInternal import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.datastore.NoOpKeyedObservable import com.android.settingslib.metadata.PersistentPreference import com.android.settingslib.metadata.PreferenceAvailabilityProvider import com.android.settingslib.metadata.PreferenceIconProvider import com.android.settingslib.metadata.PreferenceMetadata -import com.android.settingslib.metadata.PreferenceRestrictionProvider import com.android.settingslib.metadata.RangeValue import com.android.settingslib.metadata.ReadWritePermit import com.android.settingslib.preference.PreferenceBinding @@ -42,7 +40,7 @@ open class MediaVolumePreference : RangeValue, PreferenceAvailabilityProvider, PreferenceIconProvider, - PreferenceRestrictionProvider { + PreferenceRestrictionMixin { override val key: String get() = KEY @@ -58,17 +56,10 @@ open class MediaVolumePreference : override fun isAvailable(context: Context) = context.resources.getBoolean(R.bool.config_show_media_volume) - override fun isRestricted(context: Context) = - RestrictedLockUtilsInternal.hasBaseUserRestriction( - context, - UserManager.DISALLOW_ADJUST_VOLUME, - UserHandle.myUserId(), - ) || - RestrictedLockUtilsInternal.checkIfRestrictionEnforced( - context, - UserManager.DISALLOW_ADJUST_VOLUME, - UserHandle.myUserId(), - ) != null + override fun isEnabled(context: Context) = super.isEnabled(context) + + override val restrictionKey: String + get() = UserManager.DISALLOW_ADJUST_VOLUME override fun storage(context: Context): KeyValueStore { val helper = createAudioHelper(context) @@ -107,9 +98,9 @@ open class MediaVolumePreference : open fun createAudioHelper(context: Context) = AudioHelper(context) - fun updateContentDescription(preference: VolumeSeekBarPreference) { + private fun updateContentDescription(preference: VolumeSeekBarPreference) { when { - preference.isMuted() -> + preference.isMuted -> preference.updateContentDescription( preference.context.getString( R.string.volume_content_description_silent_mode, diff --git a/src/com/android/settings/notification/SeparateRingVolumePreference.kt b/src/com/android/settings/notification/SeparateRingVolumePreference.kt index 6831daad683..c6485686f52 100644 --- a/src/com/android/settings/notification/SeparateRingVolumePreference.kt +++ b/src/com/android/settings/notification/SeparateRingVolumePreference.kt @@ -24,21 +24,19 @@ import android.media.AudioManager.RINGER_MODE_SILENT import android.media.AudioManager.RINGER_MODE_VIBRATE import android.media.AudioManager.STREAM_RING import android.os.ServiceManager -import android.os.UserHandle -import android.os.UserManager.DISALLOW_ADJUST_VOLUME +import android.os.UserManager import android.os.Vibrator import android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS import android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS import androidx.preference.Preference +import com.android.settings.PreferenceRestrictionMixin import com.android.settings.R -import com.android.settingslib.RestrictedLockUtilsInternal import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.datastore.NoOpKeyedObservable import com.android.settingslib.metadata.PersistentPreference import com.android.settingslib.metadata.PreferenceAvailabilityProvider import com.android.settingslib.metadata.PreferenceIconProvider import com.android.settingslib.metadata.PreferenceMetadata -import com.android.settingslib.metadata.PreferenceRestrictionProvider import com.android.settingslib.metadata.RangeValue import com.android.settingslib.metadata.ReadWritePermit import com.android.settingslib.preference.PreferenceBinding @@ -51,7 +49,8 @@ open class SeparateRingVolumePreference : RangeValue, PreferenceAvailabilityProvider, PreferenceIconProvider, - PreferenceRestrictionProvider { + PreferenceRestrictionMixin { + override val key: String get() = KEY @@ -64,21 +63,12 @@ open class SeparateRingVolumePreference : else -> R.drawable.ic_ring_volume } - override fun isAvailable(context: Context) = !createAudioHelper(context).isSingleVolume() + override fun isAvailable(context: Context) = !createAudioHelper(context).isSingleVolume - override fun isEnabled(context: Context) = - !RestrictedLockUtilsInternal.hasBaseUserRestriction( - context, - DISALLOW_ADJUST_VOLUME, - UserHandle.myUserId(), - ) + override fun isEnabled(context: Context) = super.isEnabled(context) - override fun isRestricted(context: Context) = - RestrictedLockUtilsInternal.checkIfRestrictionEnforced( - context, - DISALLOW_ADJUST_VOLUME, - UserHandle.myUserId(), - ) != null + override val restrictionKey: String + get() = UserManager.DISALLOW_ADJUST_VOLUME override fun storage(context: Context): KeyValueStore { val helper = createAudioHelper(context) @@ -118,7 +108,7 @@ open class SeparateRingVolumePreference : open fun createAudioHelper(context: Context) = AudioHelper(context) - fun updateContentDescription(preference: VolumeSeekBarPreference) { + private fun updateContentDescription(preference: VolumeSeekBarPreference) { val context = preference.context val ringerMode = getEffectiveRingerMode(context) when (ringerMode) { @@ -152,13 +142,13 @@ open class SeparateRingVolumePreference : } } - fun getSuppressionText(context: Context): String? { + private fun getSuppressionText(context: Context): String? { val suppressor = NotificationManager.from(context).getEffectsSuppressor() val notificationManager = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE) ) - val hints = notificationManager.getHintsFromListenerNoToken() + val hints = notificationManager.hintsFromListenerNoToken return when { hintsMatch(hints) -> SuppressorHelper.getSuppressionText(context, suppressor) else -> null @@ -167,7 +157,7 @@ open class SeparateRingVolumePreference : private fun hintsMatch(hints: Int) = (hints and HINT_HOST_DISABLE_CALL_EFFECTS) != 0 || - (hints and HINT_HOST_DISABLE_EFFECTS) != 0 + (hints and HINT_HOST_DISABLE_EFFECTS) != 0 companion object { const val KEY = "separate_ring_volume" diff --git a/src/com/android/settings/notification/app/BubblePreference.java b/src/com/android/settings/notification/app/BubblePreference.java index 17deef9e6f0..73f4582034b 100644 --- a/src/com/android/settings/notification/app/BubblePreference.java +++ b/src/com/android/settings/notification/app/BubblePreference.java @@ -33,11 +33,13 @@ import androidx.preference.PreferenceViewHolder; import com.android.settings.R; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedPreferenceHelper; +import com.android.settingslib.RestrictedPreferenceHelperProvider; /** * A tri-state preference allowing a user to specify what gets to bubble. */ -public class BubblePreference extends Preference implements RadioGroup.OnCheckedChangeListener { +public class BubblePreference extends Preference implements RadioGroup.OnCheckedChangeListener, + RestrictedPreferenceHelperProvider { RestrictedPreferenceHelper mHelper; private int mSelectedPreference; @@ -64,6 +66,11 @@ public class BubblePreference extends Preference implements RadioGroup.OnChecked setLayoutResource(R.layout.bubble_preference); } + @Override + public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() { + return mHelper; + } + public void setSelectedPreference(int preference) { mSelectedPreference = preference; notifyChanged(); diff --git a/src/com/android/settings/widget/RestrictedAppPreference.java b/src/com/android/settings/widget/RestrictedAppPreference.java index c76a5de4535..86552422467 100644 --- a/src/com/android/settings/widget/RestrictedAppPreference.java +++ b/src/com/android/settings/widget/RestrictedAppPreference.java @@ -27,6 +27,7 @@ import androidx.preference.PreferenceViewHolder; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedPreferenceHelper; +import com.android.settingslib.RestrictedPreferenceHelperProvider; import com.android.settingslib.widget.AppPreference; /** @@ -34,7 +35,8 @@ import com.android.settingslib.widget.AppPreference; * {@link com.android.settingslib.RestrictedPreferenceHelper}. * Used to show policy transparency on {@link AppPreference}. */ -public class RestrictedAppPreference extends AppPreference { +public class RestrictedAppPreference extends AppPreference implements + RestrictedPreferenceHelperProvider { private RestrictedPreferenceHelper mHelper; private String userRestriction; @@ -58,6 +60,11 @@ public class RestrictedAppPreference extends AppPreference { this.userRestriction = userRestriction; } + @Override + public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() { + return mHelper; + } + @Override public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder); diff --git a/src/com/android/settings/widget/SettingsMainSwitchPreference.java b/src/com/android/settings/widget/SettingsMainSwitchPreference.java index 9f6d787e841..17d5fc88915 100644 --- a/src/com/android/settings/widget/SettingsMainSwitchPreference.java +++ b/src/com/android/settings/widget/SettingsMainSwitchPreference.java @@ -23,12 +23,14 @@ import android.util.AttributeSet; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; +import androidx.annotation.NonNull; import androidx.preference.PreferenceViewHolder; import androidx.preference.TwoStatePreference; import com.android.settings.R; import com.android.settings.widget.SettingsMainSwitchBar.OnBeforeCheckedChangeListener; import com.android.settingslib.RestrictedPreferenceHelper; +import com.android.settingslib.RestrictedPreferenceHelperProvider; import com.android.settingslib.core.instrumentation.SettingsJankMonitor; import java.util.ArrayList; @@ -40,7 +42,7 @@ import java.util.List; * to enable or disable the preferences on the page. */ public class SettingsMainSwitchPreference extends TwoStatePreference implements - OnCheckedChangeListener { + OnCheckedChangeListener, RestrictedPreferenceHelperProvider { private final List mBeforeCheckedChangeListeners = new ArrayList<>(); @@ -71,6 +73,11 @@ public class SettingsMainSwitchPreference extends TwoStatePreference implements init(context, attrs); } + @Override + public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() { + return mRestrictedHelper; + } + @Override public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder);