Skip to content

Commit 805dadb

Browse files
committed
Fix NoSuchElementException in notification content plugin
1 parent 9887ed4 commit 805dadb

File tree

5 files changed

+111
-8
lines changed

5 files changed

+111
-8
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2023 DuckDuckGo
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.duckduckgo.mobile.android.vpn.service
18+
19+
import kotlinx.coroutines.flow.Flow
20+
import kotlinx.coroutines.flow.flowOf
21+
22+
class FakeVpnEnabledNotificationContentPlugin constructor(
23+
private val isActive: Boolean,
24+
private val priority: VpnEnabledNotificationContentPlugin.VpnEnabledNotificationPriority = VpnEnabledNotificationContentPlugin.VpnEnabledNotificationPriority.NORMAL
25+
) : VpnEnabledNotificationContentPlugin {
26+
27+
override fun getInitialContent(): VpnEnabledNotificationContentPlugin.VpnEnabledNotificationContent? {
28+
return null
29+
}
30+
31+
override fun getUpdatedContent(): Flow<VpnEnabledNotificationContentPlugin.VpnEnabledNotificationContent?> {
32+
return flowOf(null)
33+
}
34+
35+
override fun getPriority(): VpnEnabledNotificationContentPlugin.VpnEnabledNotificationPriority {
36+
return this.priority
37+
}
38+
39+
override fun isActive(): Boolean = this.isActive
40+
}

app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/TrackerBlockingVpnService.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -553,8 +553,9 @@ class TrackerBlockingVpnService : VpnService(), CoroutineScope by MainScope() {
553553
}
554554

555555
private fun notifyVpnStart() {
556-
val content = vpnEnabledNotificationContentPluginPoint.getHighestPriorityPlugin().getInitialContent()
557-
val vpnNotification = content ?: VpnEnabledNotificationContentPlugin.VpnEnabledNotificationContent.EMPTY
556+
val vpnNotification =
557+
vpnEnabledNotificationContentPluginPoint.getHighestPriorityPlugin()?.getInitialContent()
558+
?: VpnEnabledNotificationContentPlugin.VpnEnabledNotificationContent.EMPTY
558559

559560
startForeground(
560561
VPN_FOREGROUND_SERVICE_ID,

app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/VpnEnabledNotificationContentPluginPoint.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ import com.duckduckgo.di.scopes.VpnScope
2727
@Suppress("unused")
2828
interface VpnEnabledNotificationContentPluginPoint
2929

30-
fun PluginPoint<VpnEnabledNotificationContentPlugin>.getHighestPriorityPlugin(): VpnEnabledNotificationContentPlugin {
31-
return getPlugins().filter { it.isActive() }.maxBy { it.getPriority().ordinal }
30+
fun PluginPoint<VpnEnabledNotificationContentPlugin>.getHighestPriorityPlugin(): VpnEnabledNotificationContentPlugin? {
31+
return runCatching { getPlugins().filter { it.isActive() }.maxByOrNull { it.getPriority().ordinal } }.getOrNull()
3232
}

app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/VpnTrackerNotificationUpdates.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@ class VpnTrackerNotificationUpdates @Inject constructor(
4343

4444
override fun onVpnStarted(coroutineScope: CoroutineScope) {
4545
job += coroutineScope.launch(dispatcherProvider.io()) {
46-
val notificationContentFlow = vpnEnabledNotificationContentPluginPoint.getHighestPriorityPlugin().getUpdatedContent()
47-
notificationContentFlow.collectLatest { content ->
48-
val vpnNotification = content ?: VpnEnabledNotificationContentPlugin.VpnEnabledNotificationContent.EMPTY
46+
val notificationContentFlow = vpnEnabledNotificationContentPluginPoint.getHighestPriorityPlugin()?.getUpdatedContent()
47+
notificationContentFlow?.let {
48+
it.collectLatest { content ->
49+
val vpnNotification = content ?: VpnEnabledNotificationContentPlugin.VpnEnabledNotificationContent.EMPTY
4950

50-
updateNotification(vpnNotification)
51+
updateNotification(vpnNotification)
52+
}
5153
}
5254
}
5355
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) 2023 DuckDuckGo
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.duckduckgo.mobile.android.vpn.service
18+
19+
import com.duckduckgo.app.global.plugins.PluginPoint
20+
import org.junit.Assert.assertEquals
21+
import org.junit.Assert.assertNull
22+
import org.junit.Test
23+
24+
class VpnEnabledNotificationContentPluginPointKtTest {
25+
@Test
26+
fun whenEmptyPluginPointThenReturnNull() {
27+
assertNull(createPluginPoint(emptyList()).getHighestPriorityPlugin())
28+
}
29+
@Test
30+
fun whenInactivePluginsThenReturnNull() {
31+
assertNull(createPluginPoint(
32+
listOf(
33+
FakeVpnEnabledNotificationContentPlugin(isActive = false),
34+
FakeVpnEnabledNotificationContentPlugin(isActive = false),
35+
)
36+
).getHighestPriorityPlugin())
37+
38+
}
39+
40+
@Test
41+
fun whenActivePluginsThenReturnThemInPriorityOrder() {
42+
val plugin = createPluginPoint(
43+
listOf(
44+
FakeVpnEnabledNotificationContentPlugin(isActive = true, VpnEnabledNotificationContentPlugin.VpnEnabledNotificationPriority.NORMAL),
45+
FakeVpnEnabledNotificationContentPlugin(isActive = true, VpnEnabledNotificationContentPlugin.VpnEnabledNotificationPriority.LOW),
46+
FakeVpnEnabledNotificationContentPlugin(isActive = true, VpnEnabledNotificationContentPlugin.VpnEnabledNotificationPriority.HIGH),
47+
)
48+
).getHighestPriorityPlugin()
49+
50+
assertEquals(VpnEnabledNotificationContentPlugin.VpnEnabledNotificationPriority.HIGH, plugin?.getPriority())
51+
}
52+
53+
private fun createPluginPoint(plugins: List<VpnEnabledNotificationContentPlugin>): PluginPoint<VpnEnabledNotificationContentPlugin> {
54+
return object : PluginPoint<VpnEnabledNotificationContentPlugin> {
55+
override fun getPlugins(): Collection<VpnEnabledNotificationContentPlugin> {
56+
return plugins
57+
}
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)