• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.spa.framework.common
18 
19 import android.os.Bundle
20 import androidx.compose.runtime.Composable
21 import androidx.compose.runtime.CompositionLocalProvider
22 import androidx.compose.runtime.ProvidedValue
23 import androidx.compose.runtime.compositionLocalOf
24 import androidx.compose.runtime.remember
25 import com.android.settingslib.spa.framework.compose.LocalNavController
26 
27 interface EntryData {
28     val pageId: String?
29         get() = null
30     val entryId: String?
31         get() = null
32     val isHighlighted: Boolean
33         get() = false
34     val arguments: Bundle?
35         get() = null
36 }
37 
38 val LocalEntryDataProvider =
<lambda>null39     compositionLocalOf<EntryData> { object : EntryData {} }
40 
41 typealias UiLayerRenderer = @Composable (arguments: Bundle?) -> Unit
42 typealias StatusDataGetter = (arguments: Bundle?) -> EntryStatusData?
43 typealias SearchDataGetter = (arguments: Bundle?) -> EntrySearchData?
44 
45 /**
46  * Defines data of a Settings entry.
47  */
48 data class SettingsEntry(
49     // The unique id of this entry, which is computed by name + owner + fromPage + toPage.
50     val id: String,
51 
52     // The name of the entry, which is used to compute the unique id, and need to be stable.
53     private val name: String,
54 
55     // The label of the entry, for better readability.
56     // For migration mapping, this should match the android:key field in the old architecture
57     // if applicable.
58     val label: String,
59 
60     // The owner page of this entry.
61     val owner: SettingsPage,
62 
63     // Defines linking of Settings entries
64     val fromPage: SettingsPage? = null,
65     val toPage: SettingsPage? = null,
66 
67     /**
68      * ========================================
69      * Defines entry attributes here.
70      * ========================================
71      */
72     val isAllowSearch: Boolean = false,
73 
74     // Indicate whether the search indexing data of entry is dynamic.
75     val isSearchDataDynamic: Boolean = false,
76 
77     // Indicate whether the status of entry is mutable.
78     // If so, for instance, we'll reindex its status for search.
79     val hasMutableStatus: Boolean = false,
80 
81     /**
82      * ========================================
83      * Defines entry APIs to get data here.
84      * ========================================
85      */
86 
87     /**
88      * API to get the status data of the entry, such as isDisabled / isSwitchOff.
89      * Returns null if this entry do NOT have any status.
90      */
<lambda>null91     private val statusDataImpl: StatusDataGetter = { null },
92 
93     /**
94      * API to get Search indexing data for this entry, such as title / keyword.
95      * Returns null if this entry do NOT support search.
96      */
<lambda>null97     private val searchDataImpl: SearchDataGetter = { null },
98 
99     /**
100      * API to Render UI of this entry directly. For now, we use it in the internal injection, to
101      * support the case that the injection page owner wants to maintain both data and UI of the
102      * injected entry. In the long term, we may deprecate the @Composable Page() API in SPP, and
103      * use each entries' UI rendering function in the page instead.
104      */
<lambda>null105     private val uiLayoutImpl: UiLayerRenderer = {},
106 ) {
containerPagenull107     fun containerPage(): SettingsPage {
108         // The Container page of the entry, which is the from-page or
109         // the owner-page if from-page is unset.
110         return fromPage ?: owner
111     }
112 
fullArgumentnull113     private fun fullArgument(runtimeArguments: Bundle? = null): Bundle {
114         return Bundle().apply {
115             if (owner.arguments != null) putAll(owner.arguments)
116             // Put runtime args later, which can override page args.
117             if (runtimeArguments != null) putAll(runtimeArguments)
118         }
119     }
120 
getStatusDatanull121     fun getStatusData(runtimeArguments: Bundle? = null): EntryStatusData? {
122         return statusDataImpl(fullArgument(runtimeArguments))
123     }
124 
getSearchDatanull125     fun getSearchData(runtimeArguments: Bundle? = null): EntrySearchData? {
126         return searchDataImpl(fullArgument(runtimeArguments))
127     }
128 
129     @Composable
UiLayoutnull130     fun UiLayout(runtimeArguments: Bundle? = null) {
131         val arguments = remember { fullArgument(runtimeArguments) }
132         CompositionLocalProvider(provideLocalEntryData(arguments)) {
133             uiLayoutImpl(arguments)
134         }
135     }
136 
137     @Composable
provideLocalEntryDatanull138     private fun provideLocalEntryData(arguments: Bundle): ProvidedValue<EntryData> {
139         val controller = LocalNavController.current
140         return LocalEntryDataProvider provides remember {
141             object : EntryData {
142                 override val pageId = containerPage().id
143                 override val entryId = id
144                 override val isHighlighted = controller.highlightEntryId == id
145                 override val arguments = arguments
146             }
147         }
148     }
149 }
150