1 /* 2 * Copyright (C) 2025 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 package com.android.settings.supervision 17 18 import android.app.Activity 19 import android.app.supervision.SupervisionManager 20 import android.content.Context 21 import android.content.Intent 22 import androidx.preference.Preference 23 import com.android.settings.R 24 import com.android.settingslib.datastore.KeyValueStore 25 import com.android.settingslib.datastore.NoOpKeyedObservable 26 import com.android.settingslib.metadata.MainSwitchPreference 27 import com.android.settingslib.metadata.PreferenceLifecycleContext 28 import com.android.settingslib.metadata.PreferenceLifecycleProvider 29 import com.android.settingslib.metadata.PreferenceMetadata 30 import com.android.settingslib.metadata.PreferenceSummaryProvider 31 import com.android.settingslib.metadata.ReadWritePermit 32 import com.android.settingslib.metadata.SensitivityLevel 33 import com.android.settingslib.preference.MainSwitchPreferenceBinding 34 import com.android.settingslib.preference.forEachRecursively 35 36 /** Main toggle to enable or disable device supervision. */ 37 class SupervisionMainSwitchPreference(context: Context) : 38 MainSwitchPreference(KEY, R.string.device_supervision_switch_title), 39 PreferenceSummaryProvider, 40 MainSwitchPreferenceBinding, 41 Preference.OnPreferenceChangeListener, 42 PreferenceLifecycleProvider { 43 44 private val supervisionMainSwitchStorage = SupervisionMainSwitchStorage(context) 45 private lateinit var lifeCycleContext: PreferenceLifecycleContext 46 47 // TODO(b/383568136): Make presence of summary conditional on whether PIN 48 // has been set up before or not. getSummarynull49 override fun getSummary(context: Context): CharSequence? = 50 context.getString(R.string.device_supervision_switch_no_pin_summary) 51 52 override fun storage(context: Context): KeyValueStore = supervisionMainSwitchStorage 53 54 override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) = 55 ReadWritePermit.DISALLOW 56 57 override fun getWritePermit(context: Context, callingPid: Int, callingUid: Int) = 58 ReadWritePermit.DISALLOW 59 60 override val sensitivityLevel: Int 61 get() = SensitivityLevel.HIGH_SENSITIVITY 62 63 override fun onCreate(context: PreferenceLifecycleContext) { 64 lifeCycleContext = context 65 } 66 onResumenull67 override fun onResume(context: PreferenceLifecycleContext) { 68 updateDependentPreferencesEnabledState( 69 context.findPreference<Preference>(KEY), 70 supervisionMainSwitchStorage.getBoolean(KEY)!!, 71 ) 72 } 73 onActivityResultnull74 override fun onActivityResult( 75 context: PreferenceLifecycleContext, 76 requestCode: Int, 77 resultCode: Int, 78 data: Intent?, 79 ): Boolean { 80 if (resultCode == Activity.RESULT_OK) { 81 val mainSwitchPreference = 82 context.requirePreference<com.android.settingslib.widget.MainSwitchPreference>(KEY) 83 val newValue = !supervisionMainSwitchStorage.getBoolean(KEY)!! 84 mainSwitchPreference.setChecked(newValue) 85 updateDependentPreferencesEnabledState(mainSwitchPreference, newValue) 86 context.notifyPreferenceChange(SupervisionPinManagementScreen.KEY) 87 } 88 89 return true 90 } 91 bindnull92 override fun bind(preference: Preference, metadata: PreferenceMetadata) { 93 super.bind(preference, metadata) 94 preference.onPreferenceChangeListener = this 95 } 96 onPreferenceChangenull97 override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { 98 if (newValue !is Boolean) return true 99 100 val intent = Intent(lifeCycleContext, ConfirmSupervisionCredentialsActivity::class.java) 101 lifeCycleContext.startActivityForResult( 102 intent, 103 REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS, 104 null, 105 ) 106 return false 107 } 108 updateDependentPreferencesEnabledStatenull109 private fun updateDependentPreferencesEnabledState( 110 preference: Preference?, 111 isChecked: Boolean, 112 ) { 113 preference?.parent?.forEachRecursively { 114 if (it.parent?.key == SupervisionDashboardScreen.SUPERVISION_DYNAMIC_GROUP_1) { 115 it.isEnabled = isChecked 116 } 117 } 118 } 119 120 @Suppress("UNCHECKED_CAST") 121 private class SupervisionMainSwitchStorage(private val context: Context) : 122 NoOpKeyedObservable<String>(), KeyValueStore { containsnull123 override fun contains(key: String) = key == KEY 124 125 override fun <T : Any> getValue(key: String, valueType: Class<T>) = 126 (context.getSystemService(SupervisionManager::class.java)?.isSupervisionEnabled() == 127 true) 128 as T 129 130 override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) { 131 if (key == KEY && value is Boolean) { 132 val supervisionManager = context.getSystemService(SupervisionManager::class.java) 133 supervisionManager?.setSupervisionEnabled(value) 134 } 135 } 136 } 137 138 companion object { 139 const val KEY = "device_supervision_switch" 140 const val REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS = 0 141 } 142 } 143