• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 
17 package com.android.settingslib.preference
18 
19 import android.content.Context
20 import android.os.Bundle
21 import androidx.preference.Preference
22 import androidx.preference.PreferenceFragmentCompat
23 import androidx.preference.PreferenceManager
24 import androidx.preference.PreferenceScreen
25 import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_ARGS
26 import com.android.settingslib.metadata.PreferenceScreenRegistry
27 
28 /** Factory to create preference screen. */
29 class PreferenceScreenFactory {
30     /** Preference manager to create/inflate preference screen. */
31     val preferenceManager: PreferenceManager
32 
33     /**
34      * Optional existing hierarchy to merge the new hierarchies into.
35      *
36      * Provide existing hierarchy will preserve the internal state (e.g. scrollbar position) for
37      * [PreferenceFragmentCompat].
38      */
39     private val rootScreen: PreferenceScreen?
40 
41     /**
42      * Factory constructor from preference fragment.
43      *
44      * The fragment must be within a valid lifecycle.
45      */
46     constructor(preferenceFragment: PreferenceFragmentCompat) {
47         preferenceManager = preferenceFragment.preferenceManager
48         rootScreen = preferenceFragment.preferenceScreen
49     }
50 
51     /** Factory constructor from [Context]. */
52     constructor(context: Context) : this(PreferenceManager(context))
53 
54     /** Factory constructor from [PreferenceManager]. */
55     constructor(preferenceManager: PreferenceManager) {
56         this.preferenceManager = preferenceManager
57         rootScreen = null
58     }
59 
60     /** Context of the factory to create preference screen. */
61     val context: Context
62         get() = preferenceManager.context
63 
64     /** Returns the existing hierarchy or create a new empty preference screen. */
getOrCreatePreferenceScreennull65     fun getOrCreatePreferenceScreen(): PreferenceScreen =
66         rootScreen ?: preferenceManager.createPreferenceScreen(context)
67 
68     /**
69      * Inflates [PreferenceScreen] from xml resource.
70      *
71      * @param xmlRes The resource ID of the XML to inflate
72      * @return The root hierarchy (if one was not provided, the new hierarchy's root)
73      */
74     fun inflate(xmlRes: Int): PreferenceScreen? =
75         if (xmlRes != 0) {
76             preferenceManager.inflateFromResource(preferenceManager.context, xmlRes, rootScreen)
77         } else {
78             rootScreen
79         }
80 
81     /**
82      * Creates [PreferenceScreen] of given key.
83      *
84      * The screen must be registered in [PreferenceScreenFactory] and provide a complete hierarchy.
85      */
createBindingScreennull86     fun createBindingScreen(
87         context: Context,
88         screenKey: String?,
89         args: Bundle?,
90     ): PreferenceScreen? {
91         val metadata = PreferenceScreenRegistry.create(context, screenKey, args) ?: return null
92         if (metadata is PreferenceScreenCreator && metadata.hasCompleteHierarchy()) {
93             return metadata.createPreferenceScreen(this)
94         }
95         return null
96     }
97 
98     companion object {
99         /** Creates [PreferenceScreen] from [PreferenceScreenRegistry]. */
100         @JvmStatic
createBindingScreennull101         fun createBindingScreen(preference: Preference): PreferenceScreen? {
102             val context = preference.context
103             val args = preference.peekExtras()?.getBundle(EXTRA_BINDING_SCREEN_ARGS)
104             val preferenceScreenCreator =
105                 (PreferenceScreenRegistry.create(context, preference.key, args)
106                     as? PreferenceScreenCreator) ?: return null
107             if (!preferenceScreenCreator.hasCompleteHierarchy()) return null
108             val factory = PreferenceScreenFactory(context)
109             val preferenceScreen = preferenceScreenCreator.createPreferenceScreen(factory)
110             factory.preferenceManager.setPreferences(preferenceScreen)
111             return preferenceScreen
112         }
113     }
114 }
115