Skip to content

Commit a2b3e3b

Browse files
authored
Merge pull request #153 from aghontpi/fix/accuradio
Fix AccuRadio ad detection not working
2 parents cbf89e5 + 4c5a6c4 commit a2b3e3b

File tree

1 file changed

+81
-39
lines changed

1 file changed

+81
-39
lines changed

app/src/main/java/bluepie/ad_silence/NotificationParser.kt

Lines changed: 81 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ package bluepie.ad_silence
33
import android.app.Notification
44
import android.content.Context
55
import android.util.Log
6+
import android.view.View
7+
import android.view.ViewGroup
8+
import android.widget.FrameLayout
9+
import android.widget.RemoteViews
10+
import android.widget.TextView
611
import bluepie.ad_silence.triggers.spotifyTrigger
712
import java.util.*
813

@@ -79,63 +84,100 @@ class NotificationParser(override var appNotification: AppNotification) :
7984
return notificationInfo
8085
}
8186

82-
private fun parseAccuradioNotification(): Boolean {
83-
Log.v(
84-
TAG,
85-
"detected ${appNotification.context.getString(R.string.accuradio)} -> ${
86-
appNotification.context.getString(R.string.accuradio_pkg_name)
87-
}"
88-
)
89-
val notification = appNotification.notification
90-
try {
91-
var fields: ArrayList<*>? = null
9287

93-
var contentView = notification.contentView;
88+
private fun extractTextFromRemoteViews(remoteViews: RemoteViews): String {
89+
return try {
90+
// Inflate the RemoteViews into a temporary container.
91+
val parent = FrameLayout(appNotification.context)
92+
val view = remoteViews.apply(appNotification.context, parent)
93+
// Traverse the inflated view tree to extract all text.
94+
extractTextFromView(view)
95+
} catch (e: Exception) {
96+
Log.e(TAG, "RemoteViews inflation failed", e)
97+
""
98+
}
99+
}
94100

95-
if (contentView == null) {
96-
contentView = notification.bigContentView;
101+
private fun extractTextFromView(view: View): String {
102+
val sb = StringBuilder()
103+
if (view is TextView) {
104+
sb.append(view.text)
105+
}
106+
if (view is ViewGroup) {
107+
for (i in 0 until view.childCount) {
108+
sb.append(" ").append(extractTextFromView(view.getChildAt(i)))
97109
}
98-
if (contentView == null) {
99-
contentView = notification.headsUpContentView;
110+
}
111+
return sb.toString().trim()
112+
}
113+
114+
private fun extractTextViaReflection(remoteViews: RemoteViews): String {
115+
var fields: ArrayList<*>? = null
116+
remoteViews.javaClass.declaredFields.forEach { field ->
117+
if (field.name == "mActions") {
118+
field.isAccessible = true
119+
fields = field.get(remoteViews) as? ArrayList<*>
100120
}
121+
}
122+
val info = LinkedList<String>()
123+
fields?.forEach { action ->
124+
action?.javaClass?.declaredFields
125+
?.firstOrNull { it.name == "value" }
126+
?.apply { isAccessible = true }
127+
?.let { field ->
128+
when (val v = field.get(action)) {
129+
is String -> info.push(v)
130+
}
131+
}
132+
}
133+
return info.joinToString(" ")
134+
}
101135

102136

103-
for (field in contentView.javaClass.declaredFields) {
104-
if (field.name == "mActions") {
105-
field.isAccessible = true
106-
fields = field.get(contentView) as ArrayList<*>
137+
private fun parseAccuradioNotification(): Boolean {
138+
Log.v(
139+
TAG,
140+
"detected ${appNotification.context.getString(R.string.accuradio)} -> " +
141+
appNotification.context.getString(R.string.accuradio_pkg_name)
142+
)
143+
val notification = appNotification.notification
144+
try {
145+
var notificationText = ""
146+
// remote views
147+
val remoteViews = notification.contentView
148+
?: notification.bigContentView
149+
?: notification.headsUpContentView
150+
151+
// Trying to inflate the RemoteViews
152+
if (remoteViews != null) {
153+
try {
154+
notificationText = extractTextFromRemoteViews(remoteViews)
155+
} catch (e: Exception) {
156+
Log.e(TAG, "RemoteViews inflation failed", e)
157+
notificationText = ""
107158
}
108-
109159
}
110-
val info = LinkedList<String>()
111-
fields?.toArray()?.forEach { it ->
112-
if (it != null) {
113-
val fieldFilter = it.javaClass.declaredFields.filter { it.name == "value" }
114-
if (fieldFilter.size == 1) {
115-
val field = fieldFilter.get(0)
116-
field.isAccessible = true
117-
118-
// necessary fields
119-
when (val v = field.get(it)) {
120-
is String -> info.push(v)
121-
}
122-
}
123-
}
160+
161+
// fallback to reflection.
162+
if (notificationText.isBlank() && remoteViews != null) {
163+
notificationText = extractTextViaReflection(remoteViews)
124164
}
125165

126-
notificationInfo = info
166+
notificationInfo = LinkedList<String>().apply { push(notificationText) }
167+
168+
// Check for ad strings.
127169
var isAd = false
128170
for (adString in appNotification.adString()) {
129-
if (info.any { it.contains(adString) }) {
171+
if (notificationText.contains(adString)) {
130172
Log.v(TAG, "detection in Accuradio: $adString")
131173
isAd = true
132174
break
133175
}
134176
}
135177
return isAd
136-
} catch (nullPointerException: NullPointerException) {
137-
Log.v(TAG, "Ad-silence exception in parsing accuradio")
138-
return false;
178+
} catch (e: Exception) {
179+
Log.v(TAG, "Ad-silence exception in parsing accuradio", e)
180+
return false
139181
}
140182
}
141183

0 commit comments

Comments
 (0)