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