Skip to content

Commit 68ea29d

Browse files
committed
Simplify message handling APIs
1 parent 55daac3 commit 68ea29d

File tree

8 files changed

+90
-71
lines changed

8 files changed

+90
-71
lines changed

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserWebViewClientTest.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ import com.duckduckgo.duckplayer.api.DuckPlayer.OpenDuckPlayerInNewTab.Unavailab
8585
import com.duckduckgo.feature.toggles.api.Toggle
8686
import com.duckduckgo.history.api.NavigationHistory
8787
import com.duckduckgo.js.messaging.api.AddDocumentStartJavaScriptPlugin
88-
import com.duckduckgo.js.messaging.api.JsMessageCallback
8988
import com.duckduckgo.js.messaging.api.WebMessagingPlugin
89+
import com.duckduckgo.js.messaging.api.WebViewCompatMessageCallback
9090
import com.duckduckgo.privacy.config.api.AmpLinks
9191
import com.duckduckgo.subscriptions.api.Subscriptions
9292
import com.duckduckgo.user.agent.api.ClientBrandHintProvider
@@ -351,7 +351,7 @@ class BrowserWebViewClientTest {
351351
@Test
352352
fun whenConfigureWebViewThenInjectJsCode() {
353353
assertEquals(0, fakeAddDocumentStartJavaScriptPlugins.plugin.countInitted)
354-
val mockCallback = mock<JsMessageCallback>()
354+
val mockCallback = mock<WebViewCompatMessageCallback>()
355355
testee.configureWebView(DuckDuckGoWebView(context), mockCallback)
356356
assertEquals(1, fakeAddDocumentStartJavaScriptPlugins.plugin.countInitted)
357357
}
@@ -360,15 +360,15 @@ class BrowserWebViewClientTest {
360360
@Test
361361
fun whenConfigureWebViewThenAddWebMessageListener() {
362362
assertFalse(fakeMessagingPlugins.plugin.registered)
363-
val mockCallback = mock<JsMessageCallback>()
363+
val mockCallback = mock<WebViewCompatMessageCallback>()
364364
testee.configureWebView(DuckDuckGoWebView(context), mockCallback)
365365
assertTrue(fakeMessagingPlugins.plugin.registered)
366366
}
367367

368368
@UiThreadTest
369369
@Test
370370
fun whenDestroyThenRemoveWebMessageListener() = runTest {
371-
val mockCallback = mock<JsMessageCallback>()
371+
val mockCallback = mock<WebViewCompatMessageCallback>()
372372
val webView = DuckDuckGoWebView(context)
373373
testee.configureWebView(webView, mockCallback)
374374
assertTrue(fakeMessagingPlugins.plugin.registered)
@@ -1343,7 +1343,7 @@ class BrowserWebViewClientTest {
13431343
}
13441344

13451345
override fun register(
1346-
jsMessageCallback: JsMessageCallback?,
1346+
jsMessageCallback: WebViewCompatMessageCallback?,
13471347
webView: WebView,
13481348
) {
13491349
registered = true

app/src/main/java/com/duckduckgo/app/browser/BrowserWebViewClient.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,9 @@ import com.duckduckgo.duckplayer.api.DuckPlayer.DuckPlayerState.ENABLED
7979
import com.duckduckgo.duckplayer.api.DuckPlayer.OpenDuckPlayerInNewTab.On
8080
import com.duckduckgo.duckplayer.impl.DUCK_PLAYER_OPEN_IN_YOUTUBE_PATH
8181
import com.duckduckgo.history.api.NavigationHistory
82-
import com.duckduckgo.js.messaging.api.WebViewCompatMessageCallback
8382
import com.duckduckgo.js.messaging.api.AddDocumentStartJavaScriptPlugin
84-
import com.duckduckgo.js.messaging.api.JsMessageCallback
8583
import com.duckduckgo.js.messaging.api.WebMessagingPlugin
84+
import com.duckduckgo.js.messaging.api.WebViewCompatMessageCallback
8685
import com.duckduckgo.malicioussiteprotection.api.MaliciousSiteProtection.Feed
8786
import com.duckduckgo.privacy.config.api.AmpLinks
8887
import com.duckduckgo.subscriptions.api.Subscriptions

content-scope-scripts/content-scope-scripts-impl/src/main/java/com/duckduckgo/contentscopescripts/impl/messaging/DebugFlagGlobalHandler.kt

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ package com.duckduckgo.contentscopescripts.impl.messaging
1818

1919
import com.duckduckgo.di.scopes.AppScope
2020
import com.duckduckgo.js.messaging.api.JsMessage
21-
import com.duckduckgo.js.messaging.api.WebViewCompatMessageCallback
21+
import com.duckduckgo.js.messaging.api.ProcessResult
22+
import com.duckduckgo.js.messaging.api.ProcessResult.SendToConsumer
2223
import com.squareup.anvil.annotations.ContributesMultibinding
2324
import javax.inject.Inject
2425
import logcat.logcat
25-
import org.json.JSONObject
2626

2727
@ContributesMultibinding(AppScope::class)
2828
class DebugFlagGlobalHandler @Inject constructor() : GlobalContentScopeJsMessageHandlersPlugin {
@@ -32,19 +32,12 @@ class DebugFlagGlobalHandler @Inject constructor() : GlobalContentScopeJsMessage
3232

3333
override fun process(
3434
jsMessage: JsMessage,
35-
jsMessageCallback: WebViewCompatMessageCallback,
36-
onResponse: (JSONObject) -> Unit,
37-
) {
35+
): ProcessResult? {
3836
if (jsMessage.method == method) {
3937
logcat { "DebugFlagGlobalHandler addDebugFlag: ${jsMessage.featureName}" }
40-
jsMessageCallback.process(
41-
featureName = jsMessage.featureName,
42-
method = jsMessage.method,
43-
id = jsMessage.id,
44-
data = jsMessage.params,
45-
onResponse = onResponse,
46-
)
38+
return SendToConsumer
4739
}
40+
return null
4841
}
4942

5043
override val method: String = "addDebugFlag"

content-scope-scripts/content-scope-scripts-impl/src/main/java/com/duckduckgo/contentscopescripts/impl/messaging/GlobalContentScopeJsMessageHandlersPlugin.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
package com.duckduckgo.contentscopescripts.impl.messaging
1818

1919
import com.duckduckgo.js.messaging.api.JsMessage
20-
import com.duckduckgo.js.messaging.api.WebViewCompatMessageCallback
21-
import org.json.JSONObject
20+
import com.duckduckgo.js.messaging.api.ProcessResult
2221

2322
/**
2423
* Plugin interface for global message handlers that should always be processed
@@ -45,13 +44,10 @@ interface GlobalJsMessageHandler {
4544
* invoking a callback so consumers can also process the message if needed.
4645
*
4746
* @param jsMessage The JavaScript message to be processed.
48-
* @param jsMessageCallback An optional callback to handle the result of the message processing.
4947
*/
5048
fun process(
5149
jsMessage: JsMessage,
52-
jsMessageCallback: WebViewCompatMessageCallback,
53-
onResponse: (JSONObject) -> Unit,
54-
)
50+
): ProcessResult?
5551

5652
/**
5753
* Method this handler can process.

content-scope-scripts/content-scope-scripts-impl/src/main/java/com/duckduckgo/contentscopescripts/impl/messaging/WebViewCompatWebCompatMessagingPlugin.kt

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import android.annotation.SuppressLint
2020
import android.webkit.WebView
2121
import androidx.annotation.VisibleForTesting
2222
import androidx.webkit.JavaScriptReplyProxy
23-
import androidx.webkit.WebViewCompat.WebMessageListener
2423
import com.duckduckgo.app.di.AppCoroutineScope
2524
import com.duckduckgo.browser.api.webviewcompat.WebViewCompatWrapper
2625
import com.duckduckgo.common.utils.plugins.PluginPoint
@@ -29,6 +28,8 @@ import com.duckduckgo.contentscopescripts.impl.WebViewCompatContentScopeScripts
2928
import com.duckduckgo.di.scopes.ActivityScope
3029
import com.duckduckgo.js.messaging.api.JsCallbackData
3130
import com.duckduckgo.js.messaging.api.JsMessage
31+
import com.duckduckgo.js.messaging.api.ProcessResult.SendResponse
32+
import com.duckduckgo.js.messaging.api.ProcessResult.SendToConsumer
3233
import com.duckduckgo.js.messaging.api.WebMessagingPlugin
3334
import com.duckduckgo.js.messaging.api.WebViewCompatMessageCallback
3435
import com.squareup.anvil.annotations.ContributesMultibinding
@@ -74,20 +75,30 @@ class WebViewCompatWebCompatMessagingPlugin @Inject constructor(
7475
.map { it.getGlobalJsMessageHandler() }
7576
.filter { it.method == jsMessage.method }
7677
.forEach { handler ->
77-
handler.process(jsMessage, jsMessageCallback) { }
78+
handler.process(jsMessage)?.let { processResult ->
79+
when (processResult) {
80+
is SendToConsumer -> {
81+
sendToConsumer(jsMessageCallback, jsMessage, replyProxy)
82+
}
83+
is SendResponse -> {
84+
onResponse(jsMessage, replyProxy)
85+
}
86+
}
87+
}
7888
}
7989

8090
// Process with feature handlers
8191
handlers.getPlugins().map { it.getJsMessageHandler() }.firstOrNull {
8292
it.methods.contains(jsMessage.method) && it.featureName == jsMessage.featureName
83-
}?.process(jsMessage, jsMessageCallback) { response: JSONObject ->
84-
val callbackData = JsCallbackData(
85-
id = jsMessage.id ?: "",
86-
params = response,
87-
featureName = jsMessage.featureName,
88-
method = jsMessage.method,
89-
)
90-
onResponse(callbackData, replyProxy)
93+
}?.process(jsMessage)?.let { processResult ->
94+
when (processResult) {
95+
is SendToConsumer -> {
96+
sendToConsumer(jsMessageCallback, jsMessage, replyProxy)
97+
}
98+
is SendResponse -> {
99+
onResponse(jsMessage, replyProxy)
100+
}
101+
}
91102
}
92103
}
93104
}
@@ -96,6 +107,41 @@ class WebViewCompatWebCompatMessagingPlugin @Inject constructor(
96107
}
97108
}
98109

110+
private fun onResponse(
111+
jsMessage: JsMessage,
112+
replyProxy: JavaScriptReplyProxy,
113+
) {
114+
val callbackData = JsCallbackData(
115+
id = jsMessage.id ?: "",
116+
params = jsMessage.params,
117+
featureName = jsMessage.featureName,
118+
method = jsMessage.method,
119+
)
120+
onResponse(callbackData, replyProxy)
121+
}
122+
123+
private fun sendToConsumer(
124+
jsMessageCallback: WebViewCompatMessageCallback,
125+
jsMessage: JsMessage,
126+
replyProxy: JavaScriptReplyProxy,
127+
) {
128+
jsMessageCallback.process(
129+
jsMessage.featureName,
130+
jsMessage.method,
131+
jsMessage.id ?: "",
132+
jsMessage.params,
133+
{ response: JSONObject ->
134+
val callbackData = JsCallbackData(
135+
id = jsMessage.id ?: "",
136+
params = response,
137+
featureName = jsMessage.featureName,
138+
method = jsMessage.method,
139+
)
140+
onResponse(callbackData, replyProxy)
141+
},
142+
)
143+
}
144+
99145
override fun register(
100146
jsMessageCallback: WebViewCompatMessageCallback?,
101147
webView: WebView,
@@ -113,7 +159,7 @@ class WebViewCompatWebCompatMessagingPlugin @Inject constructor(
113159
process(
114160
message.data ?: "",
115161
jsMessageCallback,
116-
replyProxy
162+
replyProxy,
117163
)
118164
}
119165
}.getOrElse { exception ->

content-scope-scripts/content-scope-scripts-impl/src/test/java/com/duckduckgo/contentscopescripts/impl/messaging/WebViewCompatWebCompatMessagingPluginTest.kt

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import com.duckduckgo.common.utils.plugins.PluginPoint
2525
import com.duckduckgo.contentscopescripts.api.WebViewCompatContentScopeJsMessageHandlersPlugin
2626
import com.duckduckgo.contentscopescripts.impl.WebViewCompatContentScopeScripts
2727
import com.duckduckgo.js.messaging.api.JsMessage
28+
import com.duckduckgo.js.messaging.api.ProcessResult
29+
import com.duckduckgo.js.messaging.api.ProcessResult.SendToConsumer
2830
import com.duckduckgo.js.messaging.api.WebViewCompatMessageCallback
2931
import com.duckduckgo.js.messaging.api.WebViewCompatMessageHandler
3032
import junit.framework.TestCase.assertEquals
@@ -65,16 +67,8 @@ class WebViewCompatWebCompatMessagingPluginTest {
6567
return object : WebViewCompatMessageHandler {
6668
override fun process(
6769
jsMessage: JsMessage,
68-
jsMessageCallback: WebViewCompatMessageCallback?,
69-
onResponse: (JSONObject) -> Unit,
70-
) {
71-
jsMessageCallback?.process(
72-
jsMessage.featureName,
73-
jsMessage.method,
74-
jsMessage.id,
75-
jsMessage.params,
76-
onResponse,
77-
)
70+
): ProcessResult {
71+
return SendToConsumer
7872
}
7973

8074
override val featureName: String = "webCompat"
@@ -96,16 +90,8 @@ class WebViewCompatWebCompatMessagingPluginTest {
9690

9791
override fun process(
9892
jsMessage: JsMessage,
99-
jsMessageCallback: WebViewCompatMessageCallback,
100-
onResponse: (JSONObject) -> Unit,
101-
) {
102-
jsMessageCallback.process(
103-
jsMessage.featureName,
104-
jsMessage.method,
105-
jsMessage.id,
106-
jsMessage.params,
107-
onResponse,
108-
)
93+
): ProcessResult {
94+
return SendToConsumer
10995
}
11096

11197
override val method: String = "addDebugFlag"

js-messaging/js-messaging-api/src/main/java/com/duckduckgo/js/messaging/api/WebViewCompatMessaging.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ interface WebViewCompatMessageCallback {
2828
)
2929
}
3030

31+
sealed interface ProcessResult {
32+
data object SendToConsumer : ProcessResult
33+
data class SendResponse(val response: JSONObject) : ProcessResult
34+
}
35+
3136
interface WebViewCompatMessageHandler {
3237
/**
3338
* Processes a JavaScript message received by the WebView using WebCompat APIs
@@ -40,12 +45,9 @@ interface WebViewCompatMessageHandler {
4045
* @param onResponse A callback function to send a response back to the JavaScript code.
4146
*/
4247

43-
// TODO: Simplify by removing the onResponse and callback
4448
fun process(
4549
jsMessage: JsMessage,
46-
jsMessageCallback: WebViewCompatMessageCallback?,
47-
onResponse: (JSONObject) -> Unit,
48-
)
50+
): ProcessResult?
4951

5052
/**
5153
* Name of the feature

web-compat/web-compat-impl/src/main/java/com/duckduckgo/webcompat/impl/messaging/webviewcompat/WebViewCompatWebCompatContentScopeJsMessageHandler.kt

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,24 @@
1616

1717
package com.duckduckgo.webcompat.impl.messaging.webviewcompat
1818

19-
import com.duckduckgo.contentscopescripts.api.WebCompatContentScopeJsMessageHandlersPlugin
19+
import com.duckduckgo.contentscopescripts.api.WebViewCompatContentScopeJsMessageHandlersPlugin
2020
import com.duckduckgo.di.scopes.AppScope
2121
import com.duckduckgo.js.messaging.api.JsMessage
22-
import com.duckduckgo.js.messaging.api.WebCompatMessageHandler
23-
import com.duckduckgo.js.messaging.api.WebViewCompatMessageCallback
22+
import com.duckduckgo.js.messaging.api.ProcessResult
23+
import com.duckduckgo.js.messaging.api.WebViewCompatMessageHandler
2424
import com.squareup.anvil.annotations.ContributesMultibinding
2525
import javax.inject.Inject
26-
import org.json.JSONObject
2726

2827
@ContributesMultibinding(AppScope::class)
29-
class WebViewCompatWebCompatContentScopeJsMessageHandler @Inject constructor() : WebCompatContentScopeJsMessageHandlersPlugin {
28+
class WebViewCompatWebCompatContentScopeJsMessageHandler @Inject constructor() : WebViewCompatContentScopeJsMessageHandlersPlugin {
3029

31-
override fun getJsMessageHandler(): WebCompatMessageHandler = object : WebCompatMessageHandler {
30+
override fun getJsMessageHandler(): WebViewCompatMessageHandler = object : WebViewCompatMessageHandler {
3231

3332
override fun process(
3433
jsMessage: JsMessage,
35-
jsMessageCallback: WebViewCompatMessageCallback?,
36-
onResponse: (JSONObject) -> Unit,
37-
) {
38-
if (jsMessage.id == null) return
39-
jsMessageCallback?.process(featureName, jsMessage.method, jsMessage.id, jsMessage.params, onResponse)
34+
): ProcessResult? {
35+
if (jsMessage.id == null) return null
36+
return ProcessResult.SendToConsumer
4037
}
4138

4239
override val featureName: String = "webCompat"

0 commit comments

Comments
 (0)