• 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.content.Intent
21 import android.os.Bundle
22 import android.util.Log
23 import androidx.annotation.XmlRes
24 import androidx.lifecycle.Lifecycle
25 import androidx.preference.PreferenceScreen
26 import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_ARGS
27 import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_KEY
28 import com.android.settingslib.metadata.PreferenceScreenBindingKeyProvider
29 import com.android.settingslib.metadata.PreferenceScreenRegistry
30 import com.android.settingslib.preference.PreferenceScreenBindingHelper.Companion.bindRecursively
31 import com.android.settingslib.widget.SettingsBasePreferenceFragment
32 
33 /** Fragment to display a preference screen. */
34 open class PreferenceFragment :
35     SettingsBasePreferenceFragment(), PreferenceScreenProvider, PreferenceScreenBindingKeyProvider {
36 
37     protected var preferenceScreenBindingHelper: PreferenceScreenBindingHelper? = null
38 
onCreatePreferencesnull39     override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
40         preferenceScreen = createPreferenceScreen()
41     }
42 
setPreferenceScreennull43     override fun setPreferenceScreen(preferenceScreen: PreferenceScreen?) {
44         super.setPreferenceScreen(preferenceScreen)
45         updateActivityTitle()
46     }
47 
createPreferenceScreennull48     fun createPreferenceScreen(): PreferenceScreen? =
49         createPreferenceScreen(PreferenceScreenFactory(this))
50 
51     override fun createPreferenceScreen(factory: PreferenceScreenFactory): PreferenceScreen? {
52         preferenceScreenBindingHelper?.onDestroy()
53         preferenceScreenBindingHelper = null
54 
55         val context = factory.context
56         fun createPreferenceScreenFromResource() =
57             factory.inflate(getPreferenceScreenResId(context))?.also {
58                 Log.i(TAG, "Load screen " + it.key + " from resource")
59             }
60 
61         val screenCreator =
62             getPreferenceScreenCreator(context) ?: return createPreferenceScreenFromResource()
63         val preferenceBindingFactory = screenCreator.preferenceBindingFactory
64         val preferenceHierarchy = screenCreator.getPreferenceHierarchy(context)
65         val preferenceScreen =
66             if (screenCreator.hasCompleteHierarchy()) {
67                 Log.i(TAG, "Load screen " + screenCreator.key + " from hierarchy")
68                 factory.getOrCreatePreferenceScreen().apply {
69                     inflatePreferenceHierarchy(preferenceBindingFactory, preferenceHierarchy)
70                 }
71             } else {
72                 Log.i(TAG, "Screen " + screenCreator.key + " is hybrid")
73                 createPreferenceScreenFromResource()?.also {
74                     bindRecursively(it, preferenceBindingFactory, preferenceHierarchy)
75                 } ?: return null
76             }
77 
78         preferenceScreenBindingHelper =
79             PreferenceScreenBindingHelper(
80                 context,
81                 this,
82                 preferenceBindingFactory,
83                 preferenceScreen,
84                 preferenceHierarchy,
85             )
86         return preferenceScreen
87     }
88 
89     /** Returns the xml resource to create preference screen. */
getPreferenceScreenResIdnull90     @XmlRes protected open fun getPreferenceScreenResId(context: Context): Int = 0
91 
92     protected fun getPreferenceScreenCreator(context: Context): PreferenceScreenCreator? =
93         (PreferenceScreenRegistry.create(
94                 context,
95                 getPreferenceScreenBindingKey(context),
96                 getPreferenceScreenBindingArgs(context),
97             ) as? PreferenceScreenCreator)
98             ?.run { if (isFlagEnabled(context)) this else null }
99 
getPreferenceScreenBindingKeynull100     override fun getPreferenceScreenBindingKey(context: Context): String? =
101         arguments?.getString(EXTRA_BINDING_SCREEN_KEY)
102 
103     override fun getPreferenceScreenBindingArgs(context: Context): Bundle? =
104         arguments?.getBundle(EXTRA_BINDING_SCREEN_ARGS)
105 
106     override fun onCreate(savedInstanceState: Bundle?) {
107         super.onCreate(savedInstanceState)
108         preferenceScreenBindingHelper?.onCreate()
109     }
110 
onStartnull111     override fun onStart() {
112         super.onStart()
113         preferenceScreenBindingHelper?.onStart()
114     }
115 
onResumenull116     override fun onResume() {
117         super.onResume()
118         // Even when activity has several fragments with preference screen, this will keep activity
119         // title in sync when fragment manager pops back stack.
120         updateActivityTitle()
121         preferenceScreenBindingHelper?.onResume()
122     }
123 
updateActivityTitlenull124     internal fun updateActivityTitle() {
125         if (!lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) return
126         val activity = activity ?: return
127         val title = preferenceScreen?.title ?: return
128         if (activity.title != title) activity.title = title
129     }
130 
onPausenull131     override fun onPause() {
132         preferenceScreenBindingHelper?.onPause()
133         super.onPause()
134     }
135 
onStopnull136     override fun onStop() {
137         preferenceScreenBindingHelper?.onStop()
138         super.onStop()
139     }
140 
onDestroynull141     override fun onDestroy() {
142         preferenceScreenBindingHelper?.onDestroy()
143         preferenceScreenBindingHelper = null
144         super.onDestroy()
145     }
146 
147     @Suppress("DEPRECATION")
148     @Deprecated("Deprecated in Java")
onActivityResultnull149     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
150         super.onActivityResult(requestCode, resultCode, data)
151         preferenceScreenBindingHelper?.onActivityResult(requestCode, resultCode, data)
152     }
153 
getPreferenceKeysInHierarchynull154     protected fun getPreferenceKeysInHierarchy(): Set<String> =
155         preferenceScreenBindingHelper?.let {
156             mutableSetOf<String>().apply { it.forEachRecursively { add(it.metadata.key) } }
157         } ?: setOf()
158 
159     companion object {
160         private const val TAG = "PreferenceFragment"
161     }
162 }
163