Skip to content

Commit 99f4ce9

Browse files
FreeNotifications: hook notification settings
this enables the app-level master switch
1 parent 893af74 commit 99f4ce9

File tree

3 files changed

+184
-1
lines changed

3 files changed

+184
-1
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
de.binarynoise.freeNotifications.Hook
2+
de.binarynoise.freeNotifications.SettingsHook

FreeNotifications/src/main/java/de/binarynoise/freeNotifications/Hook.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class Hook : IXposedHookLoadPackage {
115115
}
116116
}
117117

118-
private inline fun tryAndLog(message: String, block: () -> Unit) {
118+
inline fun tryAndLog(message: String, block: () -> Unit) {
119119
return try {
120120
block()
121121
log("hook $message successful!")
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package de.binarynoise.freeNotifications
2+
3+
import android.app.NotificationChannel
4+
import android.app.NotificationChannelGroup
5+
import android.app.role.RoleManager
6+
import android.content.Context
7+
import android.content.pm.ApplicationInfo
8+
import android.content.pm.PackageInfo
9+
import android.content.pm.PackageManager
10+
import android.os.Build
11+
import de.robv.android.xposed.IXposedHookLoadPackage
12+
import de.robv.android.xposed.XC_MethodHook
13+
import de.robv.android.xposed.XC_MethodReplacement
14+
import de.robv.android.xposed.XC_MethodReplacement.DO_NOTHING
15+
import de.robv.android.xposed.XposedBridge
16+
import de.robv.android.xposed.XposedHelpers
17+
import de.robv.android.xposed.callbacks.XC_LoadPackage
18+
19+
class SettingsHook : IXposedHookLoadPackage {
20+
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
21+
if (lpparam.packageName != "com.android.settings") return
22+
23+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
24+
val NotificationPreferenceControllerClass = Class.forName(
25+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) "com.android.settings.notification.app.NotificationPreferenceController"
26+
else "com.android.settings.notification.NotificationPreferenceController",
27+
false,
28+
lpparam.classLoader,
29+
)
30+
31+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
32+
tryAndLog("isAppBlockable") {
33+
XposedHelpers.findAndHookMethod(
34+
NotificationPreferenceControllerClass,
35+
"isAppBlockable",
36+
XC_MethodReplacement.returnConstant(true),
37+
)
38+
}
39+
tryAndLog("${NotificationPreferenceControllerClass.simpleName} constructor overrideBlock overrideConfigure") {
40+
XposedBridge.hookAllConstructors(
41+
NotificationPreferenceControllerClass,
42+
object : XC_MethodHook() {
43+
override fun afterHookedMethod(param: MethodHookParam) {
44+
listOf("Block", "Configure").forEach {
45+
XposedHelpers.setBooleanField(param.thisObject, "overrideCan$it", true)
46+
XposedHelpers.setBooleanField(param.thisObject, "overrideCan${it}Value", true)
47+
}
48+
}
49+
},
50+
)
51+
}
52+
tryAndLog("setOverrideCanBlock") {
53+
XposedHelpers.findAndHookMethod(
54+
NotificationPreferenceControllerClass,
55+
"setOverrideCanBlock",
56+
Boolean::class.java,
57+
DO_NOTHING,
58+
)
59+
}
60+
tryAndLog("setOverrideCanConfigure") {
61+
XposedHelpers.findAndHookMethod(
62+
NotificationPreferenceControllerClass,
63+
"setOverrideCanConfigure",
64+
Boolean::class.java,
65+
DO_NOTHING,
66+
)
67+
}
68+
}
69+
70+
tryAndLog("isChannelBlockable") {
71+
XposedHelpers.findAndHookMethod(
72+
NotificationPreferenceControllerClass,
73+
"isChannelBlockable",
74+
XC_MethodReplacement.returnConstant(true),
75+
)
76+
}
77+
tryAndLog("isChannelBlockable") {
78+
XposedHelpers.findAndHookMethod(
79+
NotificationPreferenceControllerClass,
80+
"isChannelBlockable",
81+
NotificationChannel::class.java,
82+
XC_MethodReplacement.returnConstant(true),
83+
)
84+
}
85+
tryAndLog("isChannelConfigurable") {
86+
XposedHelpers.findAndHookMethod(
87+
NotificationPreferenceControllerClass,
88+
"isChannelConfigurable",
89+
NotificationChannel::class.java,
90+
XC_MethodReplacement.returnConstant(true),
91+
)
92+
}
93+
tryAndLog("isChannelGroupBlockable") {
94+
XposedHelpers.findAndHookMethod(
95+
NotificationPreferenceControllerClass,
96+
"isChannelGroupBlockable",
97+
XC_MethodReplacement.returnConstant(true),
98+
)
99+
}
100+
tryAndLog("isChannelGroupBlockable") {
101+
XposedHelpers.findAndHookMethod(
102+
NotificationPreferenceControllerClass,
103+
"isChannelGroupBlockable",
104+
NotificationChannelGroup::class.java,
105+
XC_MethodReplacement.returnConstant(true),
106+
)
107+
}
108+
}
109+
110+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
111+
val NotificationBackendClass = Class.forName("com.android.settings.notification.NotificationBackend", false, lpparam.classLoader)
112+
val AppRowClass = Class.forName(NotificationBackendClass.name + "\$AppRow", false, lpparam.classLoader)
113+
tryAndLog("loadAppRow") {
114+
NotificationBackendClass.declaredMethods.filter { it.name == "loadAppRow" }.forEach { method ->
115+
XposedBridge.hookMethod(
116+
method,
117+
object : XC_MethodHook() {
118+
override fun afterHookedMethod(param: MethodHookParam) {
119+
val row = param.result
120+
XposedHelpers.setBooleanField(row, "systemApp", false)
121+
}
122+
},
123+
)
124+
}
125+
}
126+
tryAndLog("recordCanBeBlocked") {
127+
XposedHelpers.findAndHookMethod(
128+
NotificationBackendClass,
129+
"recordCanBeBlocked",
130+
Context::class.java,
131+
PackageManager::class.java,
132+
RoleManager::class.java,
133+
PackageInfo::class.java,
134+
AppRowClass,
135+
object : XC_MethodHook() {
136+
override fun afterHookedMethod(param: MethodHookParam) {
137+
val row = param.args[4]
138+
XposedHelpers.setBooleanField(row, "systemApp", false)
139+
}
140+
},
141+
)
142+
}
143+
tryAndLog("markAppRowWithBlockables") {
144+
XposedHelpers.findAndHookMethod(
145+
NotificationBackendClass,
146+
"markAppRowWithBlockables",
147+
Array<String>::class.java,
148+
AppRowClass,
149+
String::class.java,
150+
object : XC_MethodHook() {
151+
override fun afterHookedMethod(param: MethodHookParam) {
152+
val row = param.args[1]
153+
XposedHelpers.setBooleanField(row, "systemApp", false)
154+
}
155+
},
156+
)
157+
}
158+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
159+
tryAndLog("isSystemApp") {
160+
XposedHelpers.findAndHookMethod(
161+
NotificationBackendClass,
162+
"isSystemApp",
163+
Context::class.java,
164+
ApplicationInfo::class.java,
165+
XC_MethodReplacement.returnConstant(false),
166+
)
167+
}
168+
}
169+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
170+
tryAndLog("isBlockable") {
171+
XposedHelpers.findAndHookMethod(
172+
NotificationBackendClass,
173+
"isBlockable",
174+
Context::class.java,
175+
ApplicationInfo::class.java,
176+
XC_MethodReplacement.returnConstant(true),
177+
)
178+
}
179+
}
180+
}
181+
}
182+
}

0 commit comments

Comments
 (0)