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.tests.testutils
18 
19 import android.app.Activity
20 import android.content.Context
21 import android.os.Bundle
22 import androidx.compose.material3.Text
23 import androidx.compose.runtime.Composable
24 import androidx.navigation.NavType
25 import androidx.navigation.navArgument
26 import com.android.settingslib.spa.framework.BrowseActivity
27 import com.android.settingslib.spa.framework.common.EntrySearchData
28 import com.android.settingslib.spa.framework.common.EntryStatusData
29 import com.android.settingslib.spa.framework.common.LogCategory
30 import com.android.settingslib.spa.framework.common.LogEvent
31 import com.android.settingslib.spa.framework.common.SettingsEntry
32 import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
33 import com.android.settingslib.spa.framework.common.SettingsPage
34 import com.android.settingslib.spa.framework.common.SettingsPageProvider
35 import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
36 import com.android.settingslib.spa.framework.common.SpaEnvironment
37 import com.android.settingslib.spa.framework.common.SpaLogger
38 import com.android.settingslib.spa.framework.common.createSettingsPage
39 import com.android.settingslib.spa.widget.preference.SimplePreferenceMacro
40 
41 class SpaLoggerForTest : SpaLogger {
42     data class MsgCountKey(val msg: String, val category: LogCategory)
43     data class EventCountKey(val id: String, val event: LogEvent, val category: LogCategory)
44 
45     private val messageCount: MutableMap<MsgCountKey, Int> = mutableMapOf()
46     private val eventCount: MutableMap<EventCountKey, Int> = mutableMapOf()
47 
messagenull48     override fun message(tag: String, msg: String, category: LogCategory) {
49         val key = MsgCountKey("[$tag]$msg", category)
50         messageCount[key] = (messageCount[key] ?: 0) + 1
51     }
52 
eventnull53     override fun event(id: String, event: LogEvent, category: LogCategory, extraData: Bundle) {
54         val key = EventCountKey(id, event, category)
55         eventCount[key] = (eventCount[key] ?: 0) + 1
56     }
57 
getMessageCountnull58     fun getMessageCount(tag: String, msg: String, category: LogCategory): Int {
59         val key = MsgCountKey("[$tag]$msg", category)
60         return messageCount[key] ?: 0
61     }
62 
getEventCountnull63     fun getEventCount(id: String, event: LogEvent, category: LogCategory): Int {
64         val key = EventCountKey(id, event, category)
65         return eventCount[key] ?: 0
66     }
67 
resetnull68     fun reset() {
69         messageCount.clear()
70         eventCount.clear()
71     }
72 }
73 
74 class BlankActivity : BrowseActivity()
75 
76 object SppHome : SettingsPageProvider {
77     override val name = "SppHome"
78 
getTitlenull79     override fun getTitle(arguments: Bundle?): String {
80         return "TitleHome"
81     }
82 
buildEntrynull83     override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
84         val owner = this.createSettingsPage()
85         return listOf(
86             SppLayer1.buildInject().setLink(fromPage = owner).build(),
87             SppDialog.buildInject().setLink(fromPage = owner).build(),
88         )
89     }
90 }
91 
92 object SppDisabled : SettingsPageProvider {
93     override val name = "SppDisabled"
94 
isEnablednull95     override fun isEnabled(arguments: Bundle?): Boolean = false
96 
97     override fun getTitle(arguments: Bundle?): String {
98         return "TitleDisabled"
99     }
100 
buildEntrynull101     override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
102         val owner = this.createSettingsPage()
103         return listOf(
104             SppLayer1.buildInject().setLink(fromPage = owner).build(),
105         )
106     }
107 }
108 
109 object SppLayer1 : SettingsPageProvider {
110     override val name = "SppLayer1"
111 
getTitlenull112     override fun getTitle(arguments: Bundle?): String {
113         return "TitleLayer1"
114     }
115 
buildInjectnull116     fun buildInject(): SettingsEntryBuilder {
117         return SettingsEntryBuilder.createInject(this.createSettingsPage())
118             .setMacro {
119                 SimplePreferenceMacro(
120                     title = "SppHome to Layer1",
121                     clickRoute = name
122                 )
123             }
124     }
125 
buildEntrynull126     override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
127         val owner = this.createSettingsPage()
128         return listOf(
129             SettingsEntryBuilder.create(owner, "Layer1Entry1").build(),
130             SppLayer2.buildInject().setLink(fromPage = owner).build(),
131             SettingsEntryBuilder.create(owner, "Layer1Entry2").build(),
132         )
133     }
134 }
135 
136 object SppLayer2 : SettingsPageProvider {
137     override val name = "SppLayer2"
138 
buildInjectnull139     fun buildInject(): SettingsEntryBuilder {
140         return SettingsEntryBuilder.createInject(this.createSettingsPage())
141     }
142 
buildEntrynull143     override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
144         val owner = this.createSettingsPage()
145         return listOf(
146             SettingsEntryBuilder.create(owner, "Layer2Entry1").build(),
147             SettingsEntryBuilder.create(owner, "Layer2Entry2").build(),
148         )
149     }
150 }
151 
152 object SppDialog : SettingsPageProvider {
153     override val name = "SppDialog"
154     override val navType = SettingsPageProvider.NavType.Dialog
155 
156     const val CONTENT = "SppDialog Content"
157 
158     @Composable
Pagenull159     override fun Page(arguments: Bundle?) {
160         Text(CONTENT)
161     }
162 
buildInjectnull163     fun buildInject() = SettingsEntryBuilder.createInject(this.createSettingsPage())
164         .setMacro { SimplePreferenceMacro(title = name, clickRoute = name) }
165 }
166 
167 object SppForSearch : SettingsPageProvider {
168     override val name = "SppForSearch"
169 
buildEntrynull170     override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
171         val owner = this.createSettingsPage()
172         return listOf(
173             SettingsEntryBuilder.create(owner, "SearchStaticWithNoStatus")
174                 .setSearchDataFn { EntrySearchData(title = "SearchStaticWithNoStatus") }
175                 .build(),
176             SettingsEntryBuilder.create(owner, "SearchStaticWithMutableStatus")
177                 .setHasMutableStatus(true)
178                 .setSearchDataFn { EntrySearchData(title = "SearchStaticWithMutableStatus") }
179                 .setStatusDataFn { EntryStatusData(isSwitchOff = true) }
180                 .build(),
181             SettingsEntryBuilder.create(owner, "SearchDynamicWithMutableStatus")
182                 .setIsSearchDataDynamic(true)
183                 .setHasMutableStatus(true)
184                 .setSearchDataFn { EntrySearchData(title = "SearchDynamicWithMutableStatus") }
185                 .setStatusDataFn { EntryStatusData(isDisabled = true) }
186                 .build(),
187             SettingsEntryBuilder.create(owner, "SearchDynamicWithImmutableStatus")
188                 .setIsSearchDataDynamic(true)
189                 .setSearchDataFn {
190                     EntrySearchData(
191                         title = "SearchDynamicWithImmutableStatus",
192                         keyword = listOf("kw1", "kw2")
193                     )
194                 }
195                 .setStatusDataFn { EntryStatusData(isDisabled = true) }
196                 .build(),
197         )
198     }
199 }
200 
201 class SpaEnvironmentForTest(
202     context: Context,
203     rootPages: List<SettingsPage> = emptyList(),
204     override val browseActivityClass: Class<out Activity>? = BlankActivity::class.java,
205     override val logger: SpaLogger = object : SpaLogger {}
206 ) : SpaEnvironment(context) {
207 
<lambda>null208     override val pageProviderRepository = lazy {
209         SettingsPageProviderRepository(
210             listOf(
211                 SppHome, SppLayer1, SppLayer2,
212                 SppForSearch, SppDisabled,
213                 object : SettingsPageProvider {
214                     override val name = "SppWithParam"
215                     override val parameter = listOf(
216                         navArgument("string_param") { type = NavType.StringType },
217                         navArgument("int_param") { type = NavType.IntType },
218                     )
219                 },
220                 object : SettingsPageProvider {
221                     override val name = "SppWithRtParam"
222                     override val parameter = listOf(
223                         navArgument("string_param") { type = NavType.StringType },
224                         navArgument("int_param") { type = NavType.IntType },
225                         navArgument("rt_param") { type = NavType.StringType },
226                     )
227                 },
228                 SppDialog,
229             ),
230             rootPages
231         )
232     }
233 
createPagenull234     fun createPage(sppName: String, arguments: Bundle? = null): SettingsPage {
235         return pageProviderRepository.value
236             .getProviderOrNull(sppName)!!.createSettingsPage(arguments)
237     }
238 }
239