diff --git a/src/com/android/settings/display/AdaptiveSleepPreference.kt b/src/com/android/settings/display/AdaptiveSleepPreference.kt new file mode 100644 index 00000000000..f31959b1182 --- /dev/null +++ b/src/com/android/settings/display/AdaptiveSleepPreference.kt @@ -0,0 +1,137 @@ +/* + * 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.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.hardware.SensorPrivacyManager +import android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener +import android.hardware.SensorPrivacyManager.Sensors.CAMERA +import android.os.PowerManager +import android.os.UserManager +import android.provider.Settings +import com.android.settings.PreferenceRestrictionMixin +import com.android.settings.R +import com.android.settingslib.RestrictedSwitchPreference +import com.android.settingslib.datastore.KeyValueStore +import com.android.settingslib.datastore.KeyedObservableDelegate +import com.android.settingslib.datastore.SettingsSecureStore +import com.android.settingslib.datastore.SettingsStore +import com.android.settingslib.metadata.PreferenceAvailabilityProvider +import com.android.settingslib.metadata.PreferenceLifecycleContext +import com.android.settingslib.metadata.PreferenceLifecycleProvider +import com.android.settingslib.metadata.ReadWritePermit +import com.android.settingslib.metadata.TwoStatePreference +import com.android.settingslib.preference.PreferenceBindingPlaceholder +import com.android.settingslib.preference.SwitchPreferenceBinding + +// LINT.IfChange +class AdaptiveSleepPreference : + TwoStatePreference, + SwitchPreferenceBinding, + PreferenceLifecycleProvider, + PreferenceBindingPlaceholder, // not needed once controller class is cleaned up + PreferenceAvailabilityProvider, + PreferenceRestrictionMixin { + + private var broadcastReceiver: BroadcastReceiver? = null + private var sensorPrivacyChangedListener: OnSensorPrivacyChangedListener? = null + + override val key: String + get() = KEY + + override val title: Int + get() = R.string.adaptive_sleep_title + + override val summary: Int + get() = R.string.adaptive_sleep_description + + override fun isIndexable(context: Context) = false + + override fun isEnabled(context: Context) = + super.isEnabled(context) && context.canBeEnabled() + + override val restrictionKeys: Array + get() = arrayOf(UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT) + + override fun isAvailable(context: Context) = context.isAdaptiveSleepSupported() + + override fun createWidget(context: Context) = RestrictedSwitchPreference(context) + + override fun storage(context: Context): KeyValueStore = Storage(context) + + override fun getReadPermit(context: Context, myUid: Int, callingUid: Int) = + ReadWritePermit.ALLOW + + override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) = + ReadWritePermit.ALLOW + + @Suppress("UNCHECKED_CAST") + private class Storage( + private val context: Context, + private val settingsStore: SettingsStore = SettingsSecureStore.get(context), + ) : KeyedObservableDelegate(settingsStore), KeyValueStore { + + override fun contains(key: String) = settingsStore.contains(key) + + override fun getValue(key: String, valueType: Class) = + (context.canBeEnabled() && settingsStore.getBoolean(key) == true) as T + + override fun setValue(key: String, valueType: Class, value: T?) = + settingsStore.setBoolean(key, value as Boolean?) + } + + override fun onStart(context: PreferenceLifecycleContext) { + val receiver = + object : BroadcastReceiver() { + override fun onReceive(receiverContext: Context, intent: Intent) { + context.notifyPreferenceChange(this@AdaptiveSleepPreference) + } + } + context.registerReceiver( + receiver, + IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED), + ) + broadcastReceiver = receiver + + val listener = OnSensorPrivacyChangedListener { _, _ -> + context.notifyPreferenceChange(this) + } + SensorPrivacyManager.getInstance(context).addSensorPrivacyListener(CAMERA, listener) + sensorPrivacyChangedListener = listener + } + + override fun onStop(context: PreferenceLifecycleContext) { + broadcastReceiver?.let { context.unregisterReceiver(it) } + sensorPrivacyChangedListener?.let { + SensorPrivacyManager.getInstance(context).removeSensorPrivacyListener(it) + } + } + + companion object { + const val KEY = Settings.Secure.ADAPTIVE_SLEEP + + @Suppress("DEPRECATION") + private fun Context.canBeEnabled() = + AdaptiveSleepPreferenceController.hasSufficientPermission(packageManager) && + getSystemService(PowerManager::class.java)?.isPowerSaveMode != true && + !SensorPrivacyManager.getInstance(this).isSensorPrivacyEnabled(CAMERA) + } +} +// LINT.ThenChange(AdaptiveSleepPreferenceController.java) diff --git a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java index 4057f660899..82a8709df5e 100644 --- a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java +++ b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java @@ -42,9 +42,10 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.google.common.annotations.VisibleForTesting; +// LINT.IfChange /** The controller for Screen attention switch preference. */ public class AdaptiveSleepPreferenceController { - public static final String PREFERENCE_KEY = "adaptive_sleep"; + public static final String PREFERENCE_KEY = Settings.Secure.ADAPTIVE_SLEEP; private static final int DEFAULT_VALUE = 0; private final SensorPrivacyManager mPrivacyManager; private final RestrictionUtils mRestrictionUtils; @@ -147,3 +148,4 @@ public class AdaptiveSleepPreferenceController { Manifest.permission.CAMERA, attentionPackage) == PackageManager.PERMISSION_GRANTED; } } +// LINT.ThenChange(AdaptiveSleepPreference.kt) diff --git a/src/com/android/settings/display/ScreenTimeoutScreen.kt b/src/com/android/settings/display/ScreenTimeoutScreen.kt index 6595a4e43d3..9dcd1021621 100644 --- a/src/com/android/settings/display/ScreenTimeoutScreen.kt +++ b/src/com/android/settings/display/ScreenTimeoutScreen.kt @@ -18,7 +18,10 @@ package com.android.settings.display import android.content.Context import com.android.settings.R +import com.android.settings.Settings.ScreenTimeoutActivity import com.android.settings.flags.Flags +import com.android.settings.utils.makeLaunchIntent +import com.android.settingslib.metadata.PreferenceMetadata import com.android.settingslib.metadata.ProvidePreferenceScreen import com.android.settingslib.metadata.preferenceHierarchy import com.android.settingslib.preference.PreferenceScreenCreator @@ -39,7 +42,11 @@ class ScreenTimeoutScreen : PreferenceScreenCreator { override fun hasCompleteHierarchy() = false - override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {} + override fun getPreferenceHierarchy(context: Context) = + preferenceHierarchy(this) { +AdaptiveSleepPreference() } + + override fun getLaunchIntent(context: Context, metadata: PreferenceMetadata?) = + makeLaunchIntent(context, ScreenTimeoutActivity::class.java, metadata?.key) companion object { const val KEY = "screen_timeout" diff --git a/src/com/android/settings/display/ScreenTimeoutSettings.java b/src/com/android/settings/display/ScreenTimeoutSettings.java index 7800651fe8f..d4ca48ebfb7 100644 --- a/src/com/android/settings/display/ScreenTimeoutSettings.java +++ b/src/com/android/settings/display/ScreenTimeoutSettings.java @@ -38,6 +38,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; @@ -83,7 +84,9 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment @Override public void onReceive(Context context, Intent intent) { mAdaptiveSleepBatterySaverPreferenceController.updateVisibility(); - mAdaptiveSleepController.updatePreference(); + if (!isCatalystEnabled()) { + mAdaptiveSleepController.updatePreference(); + } } }; @@ -126,7 +129,6 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class); mInitialEntries = getResources().getStringArray(R.array.screen_timeout_entries); mInitialValues = getResources().getStringArray(R.array.screen_timeout_values); - mAdaptiveSleepController = new AdaptiveSleepPreferenceController(context); mAdaptiveSleepPermissionController = new AdaptiveSleepPermissionPreferenceController(context); mAdaptiveSleepCameraStatePreferenceController = @@ -139,8 +141,12 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment mPrivacyPreference.setSelectable(false); mPrivacyPreference.setLayoutResource( com.android.settingslib.widget.preference.footer.R.layout.preference_footer); - mPrivacyManager = SensorPrivacyManager.getInstance(context); - mPrivacyChangedListener = (sensor, enabled) -> mAdaptiveSleepController.updatePreference(); + if (!isCatalystEnabled()) { + mPrivacyManager = SensorPrivacyManager.getInstance(context); + mAdaptiveSleepController = new AdaptiveSleepPreferenceController(context); + mPrivacyChangedListener = + (sensor, enabled) -> mAdaptiveSleepController.updatePreference(); + } mAdditionalTogglePreferenceController = FeatureFactory.getFeatureFactory() .getDisplayFeatureProvider().createAdditionalPreference(context); } @@ -169,10 +175,12 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment mAdaptiveSleepPermissionController.updateVisibility(); mAdaptiveSleepCameraStatePreferenceController.updateVisibility(); mAdaptiveSleepBatterySaverPreferenceController.updateVisibility(); - mAdaptiveSleepController.updatePreference(); mContext.registerReceiver( mReceiver, new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)); - mPrivacyManager.addSensorPrivacyListener(CAMERA, mPrivacyChangedListener); + if (!isCatalystEnabled()) { + mAdaptiveSleepController.updatePreference(); + mPrivacyManager.addSensorPrivacyListener(CAMERA, mPrivacyChangedListener); + } mIsUserAuthenticated = false; FeatureFactory.getFeatureFactory().getDisplayFeatureProvider().updatePreference( mAdditionalTogglePreferenceController); @@ -182,13 +190,17 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment public void onStop() { super.onStop(); mContext.unregisterReceiver(mReceiver); - mPrivacyManager.removeSensorPrivacyListener(CAMERA, mPrivacyChangedListener); + if (!isCatalystEnabled()) { + mPrivacyManager.removeSensorPrivacyListener(CAMERA, mPrivacyChangedListener); + } } @Override public void updateCandidates() { final String defaultKey = getDefaultKey(); final PreferenceScreen screen = getPreferenceScreen(); + // Adaptive sleep preference is added to the screen when catalyst is enabled + Preference adaptiveSleepPreference = screen.findPreference(AdaptiveSleepPreference.KEY); screen.removeAll(); final List candidateList = getCandidates(); @@ -228,7 +240,13 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment if (isAdaptiveSleepSupported(getContext())) { mAdaptiveSleepPermissionController.addToScreen(screen); mAdaptiveSleepCameraStatePreferenceController.addToScreen(screen); - mAdaptiveSleepController.addToScreen(screen); + if (adaptiveSleepPreference != null) { + // reset order for appending + adaptiveSleepPreference.setOrder(Preference.DEFAULT_ORDER); + screen.addPreference(adaptiveSleepPreference); + } else { + mAdaptiveSleepController.addToScreen(screen); + } mAdaptiveSleepBatterySaverPreferenceController.addToScreen(screen); screen.addPreference(mPrivacyPreference); }