Loading packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt +12 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import kotlinx.coroutines.async import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.ensureActive import kotlinx.coroutines.launch import kotlinx.coroutines.selects.select /** A node in preference hierarchy that is associated with [PreferenceMetadata]. */ open class PreferenceHierarchyNode internal constructor(val metadata: PreferenceMetadata) { Loading Loading @@ -115,8 +116,6 @@ class PreferenceHierarchy : PreferenceHierarchyNode { * Adds a sub hierarchy with coroutine. * * Notes: * - [PreferenceLifecycleProvider] is not supported for [PreferenceMetadata] added to the async * hierarchy. * - As it is async, coroutine could be finished anytime. Consider specify an order explicitly * to achieve deterministic hierarchy. * - The sub hierarchy is flattened into current hierarchy. Loading Loading @@ -280,6 +279,17 @@ class PreferenceHierarchy : PreferenceHierarchyNode { } } /** Await until any child is available to be processed immediately. */ suspend fun awaitAnyChild() { if (children.isEmpty()) return for (child in children) if (child !is Deferred<*>) return select<Unit> { for (child in children) { if (child is Deferred<*>) child.onAwait { it } } } } /** * Traversals preference hierarchy recursively. * Loading packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenMetadata.kt +11 −2 Original line number Diff line number Diff line Loading @@ -115,14 +115,23 @@ interface PreferenceScreenMetadata : PreferenceGroup { fun getLaunchIntent(context: Context, metadata: PreferenceMetadata?): Intent? = null } /** Generator of [PreferenceHierarchy] based on given type. */ /** * Generator of [PreferenceHierarchy] based on given type. * * This interface should be used together with [PreferenceScreenMetadata] and * [PreferenceScreenMetadata.getPreferenceHierarchy] should return [generatePreferenceHierarchy] * with default preference hierarchy type. * * The UI framework could leverage [PreferenceLifecycleContext.switchPreferenceHierarchy] to switch * preference hierarchy with given type. */ interface PreferenceHierarchyGenerator<T> { /** Generates [PreferenceHierarchy] with given type. */ fun generatePreferenceHierarchy( context: Context, coroutineScope: CoroutineScope, type: T, hierarchyType: T, ): PreferenceHierarchy } Loading packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt +19 −4 Original line number Diff line number Diff line Loading @@ -184,6 +184,9 @@ abstract class PreferenceLifecycleContext(context: Context) : ContextWrapper(con */ abstract val childFragmentManager: FragmentManager /** Returns the key of current preference screen. */ abstract val preferenceScreenKey: String /** Returns the preference widget object associated with given key. */ abstract fun <T> findPreference(key: String): T? Loading @@ -192,7 +195,7 @@ abstract class PreferenceLifecycleContext(context: Context) : ContextWrapper(con * * @throws NullPointerException if preference is not found */ abstract fun <T : Any> requirePreference(key: String): T open fun <T : Any> requirePreference(key: String): T = findPreference(key)!! /** Returns the [KeyValueStore] attached to the preference of given key *on the same screen*. */ abstract fun getKeyValueStore(key: String): KeyValueStore? Loading @@ -201,10 +204,22 @@ abstract class PreferenceLifecycleContext(context: Context) : ContextWrapper(con abstract fun notifyPreferenceChange(key: String) /** * Switches preference hierarchy to given type, the screen metadata must implement * `PreferenceHierarchyGenerator`. * Switches to given preference hierarchy type for [PreferenceHierarchyGenerator]. * * [PreferenceScreenMetadata.hasCompleteHierarchy] must return true. */ abstract fun switchPreferenceHierarchy(hierarchyType: Any?) /** * Regenerates preference hierarchy. * * A new [PreferenceHierarchy] will be generated and applied to the preference screen. This is * to support the case that dynamic preference hierarchy is changed at runtime (e.g. app list * needs to be updated if new app is installed). * * [PreferenceScreenMetadata.hasCompleteHierarchy] must return true. */ open fun switchPreferenceHierarchy(type: Any?): Unit = TODO() abstract fun regeneratePreferenceHierarchy() /** * Starts activity for result, see [android.app.Activity.startActivityForResult]. Loading packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt +9 −6 Original line number Diff line number Diff line Loading @@ -72,13 +72,15 @@ interface PreferenceBinding { metadata.apply { preference.key = key val context = preference.context val isPreferenceScreen = preference is PreferenceScreen if (!isPreferenceScreen) { val preferenceIcon = metadata.getPreferenceIcon(context) if (preferenceIcon != 0) { preference.setIcon(preferenceIcon) } else { preference.icon = null } val isPreferenceScreen = preference is PreferenceScreen } val screenMetadata = this as? PreferenceScreenMetadata // extras preference.peekExtras()?.clear() Loading Loading @@ -153,6 +155,7 @@ interface PreferenceScreenCreator : PreferenceScreenMetadata, PreferenceScreenPr inflatePreferenceHierarchy( preferenceBindingFactory, getPreferenceHierarchy(context, coroutineScope), mutableMapOf(), ) } } packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt +95 −7 Original line number Diff line number Diff line Loading @@ -29,13 +29,26 @@ import androidx.preference.PreferenceScreen import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_ARGS import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_KEY import com.android.settingslib.metadata.PreferenceHierarchy import com.android.settingslib.metadata.PreferenceHierarchyGenerator import com.android.settingslib.metadata.PreferenceScreenBindingKeyProvider import com.android.settingslib.metadata.PreferenceScreenMetadata import com.android.settingslib.metadata.PreferenceScreenRegistry import com.android.settingslib.preference.PreferenceScreenBindingHelper.Companion.bindRecursively import com.android.settingslib.widget.SettingsBasePreferenceFragment import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.job /** Fragment to display a preference screen. */ /** * Fragment to display a preference screen for [PreferenceScreenMetadata]. * * If the associated [PreferenceScreenMetadata] is [PreferenceHierarchyGenerator], subclass must * override [onSaveHierarchyType] and [onRestoreHierarchyType] to manage current preference * hierarchy type. This is necessary to support configuration changes. */ open class PreferenceFragment : SettingsBasePreferenceFragment(), PreferenceScreenProvider, PreferenceScreenBindingKeyProvider { Loading @@ -43,6 +56,17 @@ open class PreferenceFragment : private var preferenceScreenCreatorInitialized = false protected var preferenceScreenBindingHelper: PreferenceScreenBindingHelper? = null private set /** * Current preference hierarchy type. * * This is used when the associated [PreferenceScreenMetadata] is * [PreferenceHierarchyGenerator]. Subclass could invoke [switchPreferenceHierarchy] to switch * preference hierarchy. */ var preferenceHierarchyType: Any? = null internal set override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { preferenceScreen = createPreferenceScreen() Loading @@ -54,7 +78,28 @@ open class PreferenceFragment : } fun createPreferenceScreen(): PreferenceScreen? = createPreferenceScreen(PreferenceScreenFactory(this), lifecycleScope) createPreferenceScreen(PreferenceScreenFactory(this), newCoroutineScope()) /** * Creates a new [CoroutineScope] for given preference hierarchy type. * * If a preference screen has multiple hierarchies for different types (see * [PreferenceHierarchyGenerator]), we need to cancel the old one and create a new * [CoroutineScope] when switch preference hierarchy. */ internal fun newCoroutineScope(): CoroutineScope { val coroutineContext = lifecycleScope.coroutineContext val type = preferenceHierarchyType?.let { "($it)" } ?: "" val coroutineExceptionHandler = CoroutineExceptionHandler { context, exception -> Log.e(TAG, "Failed on ${preferenceScreenCreator?.bindingKey} with $context", exception) } return CoroutineScope( coroutineExceptionHandler + coroutineContext + // MUST put coroutineContext before SupervisorJob SupervisorJob(coroutineContext.job) + CoroutineName("CatalystFragmentScope$type") ) } override fun createPreferenceScreen( factory: PreferenceScreenFactory, Loading @@ -75,19 +120,22 @@ open class PreferenceFragment : val screenCreator = getPreferenceScreenCreator(context) ?: return createPreferenceScreenFromResource() val preferenceBindingFactory = screenCreator.preferenceBindingFactory val preferenceHierarchy = screenCreator.getPreferenceHierarchy(context, coroutineScope) var storages: MutableMap<KeyValueStore, PreferenceDataStore> val preferenceHierarchy = newPreferenceHierarchy(context, coroutineScope) var storages = mutableMapOf<KeyValueStore, PreferenceDataStore>() val preferenceScreen = if (screenCreator.hasCompleteHierarchy()) { Log.i(TAG, "Load screen " + screenCreator.key + " from hierarchy") factory.getOrCreatePreferenceScreen().apply { storages = inflatePreferenceHierarchy(preferenceBindingFactory, preferenceHierarchy) inflatePreferenceHierarchy( preferenceBindingFactory, preferenceHierarchy, storages, ) } } else { Log.i(TAG, "Screen " + screenCreator.key + " is hybrid") createPreferenceScreenFromResource()?.also { storages = bindRecursively(it, preferenceBindingFactory, preferenceHierarchy) bindRecursively(it, preferenceBindingFactory, preferenceHierarchy, storages) } ?: return null } Loading @@ -95,6 +143,7 @@ open class PreferenceFragment : preferenceScreenBindingHelper = PreferenceScreenBindingHelper( this, coroutineScope, preferenceBindingFactory, preferenceScreen, preferenceHierarchy, Loading @@ -104,6 +153,24 @@ open class PreferenceFragment : return preferenceScreen } internal fun newPreferenceHierarchy( context: Context, coroutineScope: CoroutineScope, ): PreferenceHierarchy { val screenCreator = preferenceScreenCreator ?: throw IllegalStateException() val type = preferenceHierarchyType @Suppress("UNCHECKED_CAST") return if (type != null && (screenCreator as? PreferenceHierarchyGenerator<Any>) != null) { screenCreator.generatePreferenceHierarchy(context, coroutineScope, type) } else { screenCreator.getPreferenceHierarchy(context, coroutineScope) } } internal fun ensureHasCompleteHierarchy() { if (preferenceScreenCreator?.hasCompleteHierarchy() == false) throw IllegalStateException() } /** Returns the xml resource to create preference screen. */ @XmlRes protected open fun getPreferenceScreenResId(context: Context): Int = 0 Loading @@ -127,11 +194,32 @@ open class PreferenceFragment : override fun getPreferenceScreenBindingArgs(context: Context): Bundle? = arguments?.getBundle(EXTRA_BINDING_SCREEN_ARGS) /** * Switches to given preference hierarchy type. * * The associated preference screen metadata must be [PreferenceHierarchyGenerator] and its * [PreferenceScreenMetadata.hasCompleteHierarchy] must return true. */ protected fun switchPreferenceHierarchy(type: Any?) = preferenceScreenBindingHelper?.preferenceLifecycleContext?.switchPreferenceHierarchy(type) override fun onCreate(savedInstanceState: Bundle?) { preferenceHierarchyType = onRestoreHierarchyType(savedInstanceState) super.onCreate(savedInstanceState) preferenceScreenBindingHelper?.onCreate() } /** Restores preference hierarchy type from saved state. */ open fun onRestoreHierarchyType(savedInstanceState: Bundle?): Any? = null override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) preferenceHierarchyType?.let { onSaveHierarchyType(outState, it) } } /** Saves preference hierarchy type to state. */ open fun onSaveHierarchyType(outState: Bundle, hierarchyType: Any) {} override fun onStart() { super.onStart() preferenceScreenBindingHelper?.onStart() Loading Loading
packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt +12 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import kotlinx.coroutines.async import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.ensureActive import kotlinx.coroutines.launch import kotlinx.coroutines.selects.select /** A node in preference hierarchy that is associated with [PreferenceMetadata]. */ open class PreferenceHierarchyNode internal constructor(val metadata: PreferenceMetadata) { Loading Loading @@ -115,8 +116,6 @@ class PreferenceHierarchy : PreferenceHierarchyNode { * Adds a sub hierarchy with coroutine. * * Notes: * - [PreferenceLifecycleProvider] is not supported for [PreferenceMetadata] added to the async * hierarchy. * - As it is async, coroutine could be finished anytime. Consider specify an order explicitly * to achieve deterministic hierarchy. * - The sub hierarchy is flattened into current hierarchy. Loading Loading @@ -280,6 +279,17 @@ class PreferenceHierarchy : PreferenceHierarchyNode { } } /** Await until any child is available to be processed immediately. */ suspend fun awaitAnyChild() { if (children.isEmpty()) return for (child in children) if (child !is Deferred<*>) return select<Unit> { for (child in children) { if (child is Deferred<*>) child.onAwait { it } } } } /** * Traversals preference hierarchy recursively. * Loading
packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenMetadata.kt +11 −2 Original line number Diff line number Diff line Loading @@ -115,14 +115,23 @@ interface PreferenceScreenMetadata : PreferenceGroup { fun getLaunchIntent(context: Context, metadata: PreferenceMetadata?): Intent? = null } /** Generator of [PreferenceHierarchy] based on given type. */ /** * Generator of [PreferenceHierarchy] based on given type. * * This interface should be used together with [PreferenceScreenMetadata] and * [PreferenceScreenMetadata.getPreferenceHierarchy] should return [generatePreferenceHierarchy] * with default preference hierarchy type. * * The UI framework could leverage [PreferenceLifecycleContext.switchPreferenceHierarchy] to switch * preference hierarchy with given type. */ interface PreferenceHierarchyGenerator<T> { /** Generates [PreferenceHierarchy] with given type. */ fun generatePreferenceHierarchy( context: Context, coroutineScope: CoroutineScope, type: T, hierarchyType: T, ): PreferenceHierarchy } Loading
packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt +19 −4 Original line number Diff line number Diff line Loading @@ -184,6 +184,9 @@ abstract class PreferenceLifecycleContext(context: Context) : ContextWrapper(con */ abstract val childFragmentManager: FragmentManager /** Returns the key of current preference screen. */ abstract val preferenceScreenKey: String /** Returns the preference widget object associated with given key. */ abstract fun <T> findPreference(key: String): T? Loading @@ -192,7 +195,7 @@ abstract class PreferenceLifecycleContext(context: Context) : ContextWrapper(con * * @throws NullPointerException if preference is not found */ abstract fun <T : Any> requirePreference(key: String): T open fun <T : Any> requirePreference(key: String): T = findPreference(key)!! /** Returns the [KeyValueStore] attached to the preference of given key *on the same screen*. */ abstract fun getKeyValueStore(key: String): KeyValueStore? Loading @@ -201,10 +204,22 @@ abstract class PreferenceLifecycleContext(context: Context) : ContextWrapper(con abstract fun notifyPreferenceChange(key: String) /** * Switches preference hierarchy to given type, the screen metadata must implement * `PreferenceHierarchyGenerator`. * Switches to given preference hierarchy type for [PreferenceHierarchyGenerator]. * * [PreferenceScreenMetadata.hasCompleteHierarchy] must return true. */ abstract fun switchPreferenceHierarchy(hierarchyType: Any?) /** * Regenerates preference hierarchy. * * A new [PreferenceHierarchy] will be generated and applied to the preference screen. This is * to support the case that dynamic preference hierarchy is changed at runtime (e.g. app list * needs to be updated if new app is installed). * * [PreferenceScreenMetadata.hasCompleteHierarchy] must return true. */ open fun switchPreferenceHierarchy(type: Any?): Unit = TODO() abstract fun regeneratePreferenceHierarchy() /** * Starts activity for result, see [android.app.Activity.startActivityForResult]. Loading
packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt +9 −6 Original line number Diff line number Diff line Loading @@ -72,13 +72,15 @@ interface PreferenceBinding { metadata.apply { preference.key = key val context = preference.context val isPreferenceScreen = preference is PreferenceScreen if (!isPreferenceScreen) { val preferenceIcon = metadata.getPreferenceIcon(context) if (preferenceIcon != 0) { preference.setIcon(preferenceIcon) } else { preference.icon = null } val isPreferenceScreen = preference is PreferenceScreen } val screenMetadata = this as? PreferenceScreenMetadata // extras preference.peekExtras()?.clear() Loading Loading @@ -153,6 +155,7 @@ interface PreferenceScreenCreator : PreferenceScreenMetadata, PreferenceScreenPr inflatePreferenceHierarchy( preferenceBindingFactory, getPreferenceHierarchy(context, coroutineScope), mutableMapOf(), ) } }
packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt +95 −7 Original line number Diff line number Diff line Loading @@ -29,13 +29,26 @@ import androidx.preference.PreferenceScreen import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_ARGS import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_KEY import com.android.settingslib.metadata.PreferenceHierarchy import com.android.settingslib.metadata.PreferenceHierarchyGenerator import com.android.settingslib.metadata.PreferenceScreenBindingKeyProvider import com.android.settingslib.metadata.PreferenceScreenMetadata import com.android.settingslib.metadata.PreferenceScreenRegistry import com.android.settingslib.preference.PreferenceScreenBindingHelper.Companion.bindRecursively import com.android.settingslib.widget.SettingsBasePreferenceFragment import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.job /** Fragment to display a preference screen. */ /** * Fragment to display a preference screen for [PreferenceScreenMetadata]. * * If the associated [PreferenceScreenMetadata] is [PreferenceHierarchyGenerator], subclass must * override [onSaveHierarchyType] and [onRestoreHierarchyType] to manage current preference * hierarchy type. This is necessary to support configuration changes. */ open class PreferenceFragment : SettingsBasePreferenceFragment(), PreferenceScreenProvider, PreferenceScreenBindingKeyProvider { Loading @@ -43,6 +56,17 @@ open class PreferenceFragment : private var preferenceScreenCreatorInitialized = false protected var preferenceScreenBindingHelper: PreferenceScreenBindingHelper? = null private set /** * Current preference hierarchy type. * * This is used when the associated [PreferenceScreenMetadata] is * [PreferenceHierarchyGenerator]. Subclass could invoke [switchPreferenceHierarchy] to switch * preference hierarchy. */ var preferenceHierarchyType: Any? = null internal set override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { preferenceScreen = createPreferenceScreen() Loading @@ -54,7 +78,28 @@ open class PreferenceFragment : } fun createPreferenceScreen(): PreferenceScreen? = createPreferenceScreen(PreferenceScreenFactory(this), lifecycleScope) createPreferenceScreen(PreferenceScreenFactory(this), newCoroutineScope()) /** * Creates a new [CoroutineScope] for given preference hierarchy type. * * If a preference screen has multiple hierarchies for different types (see * [PreferenceHierarchyGenerator]), we need to cancel the old one and create a new * [CoroutineScope] when switch preference hierarchy. */ internal fun newCoroutineScope(): CoroutineScope { val coroutineContext = lifecycleScope.coroutineContext val type = preferenceHierarchyType?.let { "($it)" } ?: "" val coroutineExceptionHandler = CoroutineExceptionHandler { context, exception -> Log.e(TAG, "Failed on ${preferenceScreenCreator?.bindingKey} with $context", exception) } return CoroutineScope( coroutineExceptionHandler + coroutineContext + // MUST put coroutineContext before SupervisorJob SupervisorJob(coroutineContext.job) + CoroutineName("CatalystFragmentScope$type") ) } override fun createPreferenceScreen( factory: PreferenceScreenFactory, Loading @@ -75,19 +120,22 @@ open class PreferenceFragment : val screenCreator = getPreferenceScreenCreator(context) ?: return createPreferenceScreenFromResource() val preferenceBindingFactory = screenCreator.preferenceBindingFactory val preferenceHierarchy = screenCreator.getPreferenceHierarchy(context, coroutineScope) var storages: MutableMap<KeyValueStore, PreferenceDataStore> val preferenceHierarchy = newPreferenceHierarchy(context, coroutineScope) var storages = mutableMapOf<KeyValueStore, PreferenceDataStore>() val preferenceScreen = if (screenCreator.hasCompleteHierarchy()) { Log.i(TAG, "Load screen " + screenCreator.key + " from hierarchy") factory.getOrCreatePreferenceScreen().apply { storages = inflatePreferenceHierarchy(preferenceBindingFactory, preferenceHierarchy) inflatePreferenceHierarchy( preferenceBindingFactory, preferenceHierarchy, storages, ) } } else { Log.i(TAG, "Screen " + screenCreator.key + " is hybrid") createPreferenceScreenFromResource()?.also { storages = bindRecursively(it, preferenceBindingFactory, preferenceHierarchy) bindRecursively(it, preferenceBindingFactory, preferenceHierarchy, storages) } ?: return null } Loading @@ -95,6 +143,7 @@ open class PreferenceFragment : preferenceScreenBindingHelper = PreferenceScreenBindingHelper( this, coroutineScope, preferenceBindingFactory, preferenceScreen, preferenceHierarchy, Loading @@ -104,6 +153,24 @@ open class PreferenceFragment : return preferenceScreen } internal fun newPreferenceHierarchy( context: Context, coroutineScope: CoroutineScope, ): PreferenceHierarchy { val screenCreator = preferenceScreenCreator ?: throw IllegalStateException() val type = preferenceHierarchyType @Suppress("UNCHECKED_CAST") return if (type != null && (screenCreator as? PreferenceHierarchyGenerator<Any>) != null) { screenCreator.generatePreferenceHierarchy(context, coroutineScope, type) } else { screenCreator.getPreferenceHierarchy(context, coroutineScope) } } internal fun ensureHasCompleteHierarchy() { if (preferenceScreenCreator?.hasCompleteHierarchy() == false) throw IllegalStateException() } /** Returns the xml resource to create preference screen. */ @XmlRes protected open fun getPreferenceScreenResId(context: Context): Int = 0 Loading @@ -127,11 +194,32 @@ open class PreferenceFragment : override fun getPreferenceScreenBindingArgs(context: Context): Bundle? = arguments?.getBundle(EXTRA_BINDING_SCREEN_ARGS) /** * Switches to given preference hierarchy type. * * The associated preference screen metadata must be [PreferenceHierarchyGenerator] and its * [PreferenceScreenMetadata.hasCompleteHierarchy] must return true. */ protected fun switchPreferenceHierarchy(type: Any?) = preferenceScreenBindingHelper?.preferenceLifecycleContext?.switchPreferenceHierarchy(type) override fun onCreate(savedInstanceState: Bundle?) { preferenceHierarchyType = onRestoreHierarchyType(savedInstanceState) super.onCreate(savedInstanceState) preferenceScreenBindingHelper?.onCreate() } /** Restores preference hierarchy type from saved state. */ open fun onRestoreHierarchyType(savedInstanceState: Bundle?): Any? = null override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) preferenceHierarchyType?.let { onSaveHierarchyType(outState, it) } } /** Saves preference hierarchy type to state. */ open fun onSaveHierarchyType(outState: Bundle, hierarchyType: Any) {} override fun onStart() { super.onStart() preferenceScreenBindingHelper?.onStart() Loading