@@ -41,9 +41,18 @@ object HookPrefs {
4141 const val KEY_ENABLE_PACKAGE_VISIBILITY_BYPASS = " enable_package_visibility_bypass"
4242 const val KEY_REQUEST_CACHE_EXPIRATION = " request_cache_expiration"
4343
44- private val jsonFormat = Json {
45- ignoreUnknownKeys = true
46- prettyPrint = true
44+ private val VISIBILITY_RELEVANT_KEY_PREFIXES = arrayOf(
45+ " switch_one_" , " switch_two_" , " switch_three_" , " switch_four_" ,
46+ " switch_five_" , " switch_six_" , " switch_seven_" , " switch_eight_" ,
47+ " switch_nine_" , " overall_hook_enabled_"
48+ )
49+ private val VISIBILITY_RELEVANT_EXACT_KEYS = setOf (
50+ KEY_ENABLE_PACKAGE_VISIBILITY_BYPASS
51+ )
52+
53+ private val jsonFormat = Json {
54+ ignoreUnknownKeys = true
55+ prettyPrint = true
4756 isLenient = true
4857 }
4958
@@ -78,7 +87,7 @@ object HookPrefs {
7887
7988 private val generalSettingsCache = MutableStateFlow <JsonObject ?>(null )
8089 val generalSettingsFlow = generalSettingsCache.asStateFlow()
81-
90+
8291 private val cacheLock = Any ()
8392
8493 private fun getSettingsJson (): JsonObject {
@@ -90,31 +99,35 @@ object HookPrefs {
9099 if (cachedAgain != null ) return cachedAgain
91100
92101 val jsonObject = readSettingsFromFile()
93- if (jsonObject != null ) {
94- generalSettingsCache.value = jsonObject
95- return jsonObject
96- } else {
97- return JsonObject (emptyMap())
98- }
102+ generalSettingsCache.value = jsonObject ? : JsonObject (emptyMap())
103+ return generalSettingsCache.value!!
99104 }
100105 }
101106
102- private fun updateSetting (transform : (MutableMap <String , JsonElement >) -> Unit ) {
107+ private fun updateSetting (
108+ affectedKeys : Set <String > = emptySet(),
109+ transform : (MutableMap <String , JsonElement >) -> Unit
110+ ) {
103111 synchronized(cacheLock) {
104- val baseline = generalSettingsCache.value ? : readSettingsFromFile() ? : JsonObject (emptyMap())
105-
112+ val baseline = generalSettingsCache.value
113+ ? : readSettingsFromFile()
114+ ? : JsonObject (emptyMap())
106115 val mutableMap = baseline.toMutableMap()
107116 transform(mutableMap)
108- val newJson = JsonObject (mutableMap)
109- generalSettingsCache.value = newJson
117+ generalSettingsCache.value = JsonObject (mutableMap)
118+ }
119+
120+ val shouldNotify = affectedKeys.any { key ->
121+ key == KEY_ENABLE_PACKAGE_VISIBILITY_BYPASS ||
122+ VISIBILITY_RELEVANT_KEY_PREFIXES .any { key.startsWith(it) }
110123 }
111124
112125 ioScope.launch {
113126 try {
114- val currentLatestJson = generalSettingsCache.value ? : return @launch
115- val jsonString = jsonFormat.encodeToString(currentLatestJson )
127+ val latestJson = generalSettingsCache.value ? : return @launch
128+ val jsonString = jsonFormat.encodeToString(latestJson )
116129
117- if (writeTextToFile(FILE_GENERAL_SETTINGS , jsonString)) {
130+ if (writeTextToFile(FILE_GENERAL_SETTINGS , jsonString) && shouldNotify ) {
118131 closeApp.sendBroadcast(
119132 Intent (" com.close.hook.ads.ACTION_UPDATE_PKG_VISIBILITY" ).apply {
120133 setPackage(" android" )
@@ -129,48 +142,40 @@ object HookPrefs {
129142
130143 fun getBoolean (key : String , defaultValue : Boolean ): Boolean {
131144 val element = getSettingsJson()[key]
132- return if (element is JsonPrimitive ) {
133- element.booleanOrNull ? : defaultValue
134- } else {
135- defaultValue
136- }
145+ return if (element is JsonPrimitive ) element.booleanOrNull ? : defaultValue
146+ else defaultValue
137147 }
138148
139149 fun setBoolean (key : String , value : Boolean ) {
140- updateSetting { it[key] = JsonPrimitive (value) }
150+ updateSetting(affectedKeys = setOf (key)) { it[key] = JsonPrimitive (value) }
141151 }
142-
152+
143153 fun getLong (key : String , defaultValue : Long ): Long {
144154 val element = getSettingsJson()[key]
145155 return if (element is JsonPrimitive ) {
146156 element.longOrNull ? : element.contentOrNull?.toLongOrNull() ? : defaultValue
147- } else {
148- defaultValue
149- }
157+ } else defaultValue
150158 }
151159
152160 fun setLong (key : String , value : Long ) {
153- updateSetting { it[key] = JsonPrimitive (value) }
161+ updateSetting(affectedKeys = setOf (key)) { it[key] = JsonPrimitive (value) }
154162 }
155163
156164 fun getString (key : String , defaultValue : String? ): String? {
157165 val element = getSettingsJson()[key]
158- return if (element is JsonPrimitive ) {
159- element.contentOrNull ? : defaultValue
160- } else {
161- defaultValue
162- }
166+ return if (element is JsonPrimitive ) element.contentOrNull ? : defaultValue
167+ else defaultValue
163168 }
164169
165170 fun setString (key : String , value : String? ) {
166- updateSetting {
171+ updateSetting(affectedKeys = setOf (key)) {
167172 if (value == null ) it.remove(key) else it[key] = JsonPrimitive (value)
168173 }
169174 }
170175
171176 fun setMultiple (updates : Map <String , Any >) {
172177 if (updates.isEmpty()) return
173- updateSetting { map ->
178+ updateSetting(affectedKeys = updates.keys) { map ->
174179 updates.forEach { (k, v) ->
175180 val jsonElement = when (v) {
176181 is Boolean -> JsonPrimitive (v)
@@ -184,29 +189,25 @@ object HookPrefs {
184189 }
185190
186191 fun remove (key : String ) {
187- updateSetting { it.remove(key) }
192+ updateSetting(affectedKeys = setOf (key)) { it.remove(key) }
188193 }
189194
190195 fun clear () {
191196 updateSetting { it.clear() }
192197 }
193198
194- fun contains (key : String ): Boolean {
195- return getSettingsJson().containsKey(key)
196- }
199+ fun contains (key : String ): Boolean = getSettingsJson().containsKey(key)
197200
198201 fun getAll (): Map <String , Any ?> {
199202 val json = getSettingsJson()
200203 return json.mapValues { entry ->
201204 val primitive = entry.value as ? JsonPrimitive
202205 when {
203206 primitive?.isString == true -> primitive.content
204- primitive != null -> {
205- primitive.booleanOrNull
206- ? : primitive.longOrNull
207- ? : primitive.doubleOrNull
208- ? : primitive.content
209- }
207+ primitive != null -> primitive.booleanOrNull
208+ ? : primitive.longOrNull
209+ ? : primitive.doubleOrNull
210+ ? : primitive.content
210211 else -> entry.value.toString()
211212 }
212213 }
@@ -216,11 +217,11 @@ object HookPrefs {
216217
217218 fun getCustomHookConfigs (packageName : String? ): List <CustomHookInfo > {
218219 val effectiveKey = packageName ? : GLOBAL_KEY
219-
220+
220221 customHookCache[effectiveKey]?.let { return it }
221222
222223 val content = readAllTextFromFile(buildFileName(FILE_PREFIX_CUSTOM_HOOK , effectiveKey))
223-
224+
224225 if (content == null ) {
225226 Log .w(TAG , " Service unavailable. Returning empty custom hooks without caching." )
226227 return emptyList()
@@ -236,14 +237,14 @@ object HookPrefs {
236237 emptyList()
237238 }
238239 }
239-
240+
240241 customHookCache[effectiveKey] = result
241242 return result
242243 }
243244
244245 fun setCustomHookConfigs (packageName : String? , configs : List <CustomHookInfo >) {
245246 val effectiveKey = packageName ? : GLOBAL_KEY
246-
247+
247248 if (configs.isEmpty()) {
248249 customHookCache.remove(effectiveKey)
249250 } else {
@@ -277,9 +278,7 @@ object HookPrefs {
277278
278279 private fun readSettingsFromFile (): JsonObject ? {
279280 val content = readAllTextFromFile(FILE_GENERAL_SETTINGS ) ? : return null
280-
281281 if (content.isBlank()) return JsonObject (emptyMap())
282-
283282 return try {
284283 jsonFormat.parseToJsonElement(content) as ? JsonObject ? : JsonObject (emptyMap())
285284 } catch (e: Exception ) {
@@ -294,22 +293,21 @@ object HookPrefs {
294293 Log .w(TAG , " fileAccessor is null. Framework IPC disconnected." )
295294 return null
296295 }
297-
296+
298297 try {
299298 val files = accessor.listRemoteFiles()
300- if (files == null || ! files.contains(fileName)) {
301- return " "
302- }
299+ if (files == null || ! files.contains(fileName)) return " "
303300 } catch (e: Exception ) {
304301 Log .e(TAG , " Error checking remote files (IPC failure)" , e)
305302 return null
306303 }
307304
308305 return try {
309306 accessor.openRemoteFile(fileName, " r" )?.use { pfd ->
310- InputStreamReader (ParcelFileDescriptor .AutoCloseInputStream (pfd), StandardCharsets .UTF_8 ).use {
311- it.readText()
312- }
307+ InputStreamReader (
308+ ParcelFileDescriptor .AutoCloseInputStream (pfd),
309+ StandardCharsets .UTF_8
310+ ).use { it.readText() }
313311 } ? : " "
314312 } catch (e: Exception ) {
315313 Log .e(TAG , " Error reading remote file" , e)
@@ -323,9 +321,9 @@ object HookPrefs {
323321 accessor.openRemoteFile(fileName, " rw" )?.use { pfd ->
324322 ParcelFileDescriptor .AutoCloseOutputStream (pfd).use { fos ->
325323 fos.channel.truncate(0 )
326- fos.bufferedWriter(StandardCharsets .UTF_8 ).use { writer ->
327- writer.write(content)
328- }
324+ val writer = fos.bufferedWriter(StandardCharsets .UTF_8 )
325+ writer.write(content)
326+ writer.flush()
329327 }
330328 }
331329 true
@@ -344,31 +342,24 @@ object HookPrefs {
344342 }
345343 }
346344
347- internal fun buildKey (prefix : String , packageName : String? ): String {
348- return prefix + (packageName ? : GLOBAL_KEY )
349- }
345+ internal fun buildKey (prefix : String , packageName : String? ): String =
346+ prefix + (packageName ? : GLOBAL_KEY )
350347
351- private fun buildFileName (prefix : String , key : String ): String {
352- return " $prefix$key .json"
353- }
348+ private fun buildFileName (prefix : String , key : String ): String = " $prefix$key .json"
354349
355- fun getOverallHookEnabled (packageName : String? ): Boolean {
356- return getBoolean(buildKey(KEY_PREFIX_OVERALL_HOOK , packageName), false )
357- }
350+ fun getOverallHookEnabled (packageName : String? ): Boolean =
351+ getBoolean(buildKey(KEY_PREFIX_OVERALL_HOOK , packageName), false )
358352
359353 fun setOverallHookEnabled (packageName : String? , isEnabled : Boolean ) {
360354 setBoolean(buildKey(KEY_PREFIX_OVERALL_HOOK , packageName), isEnabled)
361355 }
362356
363- fun getEnableLogging (packageName : String? ): Boolean {
364- return getBoolean(buildKey(KEY_PREFIX_ENABLE_LOGGING , packageName), false )
365- }
357+ fun getEnableLogging (packageName : String? ): Boolean =
358+ getBoolean(buildKey(KEY_PREFIX_ENABLE_LOGGING , packageName), false )
366359
367360 fun setEnableLogging (packageName : String? , isEnabled : Boolean ) {
368361 setBoolean(buildKey(KEY_PREFIX_ENABLE_LOGGING , packageName), isEnabled)
369362 }
370363
371- fun getRequestCacheExpiration (): Long {
372- return getString(KEY_REQUEST_CACHE_EXPIRATION , " 5" )?.toLongOrNull() ? : 5L
373- }
364+ fun getRequestCacheExpiration (): Long = getLong(KEY_REQUEST_CACHE_EXPIRATION , 5L )
374365}
0 commit comments