Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Wrap persistent connection service in try Cherry-pick [WPB-11113] #3547

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,17 @@

package com.wire.android.feature

import android.content.Context
import android.content.Intent
import android.os.Build
import com.wire.android.appLogger
import com.wire.android.services.PersistentWebSocketService
import dagger.hilt.android.qualifiers.ApplicationContext
import com.wire.android.services.ServicesManager
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class StartPersistentWebsocketIfNecessaryUseCase @Inject constructor(
@ApplicationContext private val appContext: Context,
private val servicesManager: ServicesManager,
private val shouldStartPersistentWebSocketService: ShouldStartPersistentWebSocketServiceUseCase
) {
suspend operator fun invoke() {
val persistentWebSocketServiceIntent = PersistentWebSocketService.newIntent(appContext)
shouldStartPersistentWebSocketService().let {
when (it) {
is ShouldStartPersistentWebSocketServiceUseCase.Result.Failure -> {
Expand All @@ -43,33 +38,17 @@ class StartPersistentWebsocketIfNecessaryUseCase @Inject constructor(

is ShouldStartPersistentWebSocketServiceUseCase.Result.Success -> {
if (it.shouldStartPersistentWebSocketService) {
startForegroundService(persistentWebSocketServiceIntent)
appLogger.i("${TAG}: Starting PersistentWebsocketService")
servicesManager.startPersistentWebSocketService()
} else {
appLogger.i("${TAG}: Stopping PersistentWebsocketService, no user with persistent web socket enabled found")
appContext.stopService(persistentWebSocketServiceIntent)
servicesManager.stopPersistentWebSocketService()
}
}
}
}
}

private fun startForegroundService(persistentWebSocketServiceIntent: Intent) {
when {
PersistentWebSocketService.isServiceStarted -> {
appLogger.i("${TAG}: PersistentWebsocketService already started, not starting again")
}

else -> {
appLogger.i("${TAG}: Starting PersistentWebsocketService")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
appContext.startForegroundService(persistentWebSocketServiceIntent)
} else {
appContext.startService(persistentWebSocketServiceIntent)
}
}
}
}

companion object {
const val TAG = "StartPersistentWebsocketIfNecessaryUseCase"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@

package com.wire.android.services

import android.app.ForegroundServiceStartNotAllowedException
import android.app.Notification
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.app.ServiceCompat
Expand Down Expand Up @@ -131,12 +133,29 @@ class PersistentWebSocketService : Service() {
.setOngoing(true)
.build()

ServiceCompat.startForeground(
this,
NotificationIds.PERSISTENT_NOTIFICATION_ID.ordinal,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
try {
ServiceCompat.startForeground(
this,
NotificationIds.PERSISTENT_NOTIFICATION_ID.ordinal,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
)
} catch (e: ForegroundServiceStartNotAllowedException) {
// ForegroundServiceStartNotAllowedException may be thrown on restarting service from the background.
// this is the only suggested workaround from google for now.
// https://issuetracker.google.com/issues/307329994#comment86
appLogger.e("Failure while starting foreground: $e")
stopSelf()
}
} else {
ServiceCompat.startForeground(
this,
NotificationIds.PERSISTENT_NOTIFICATION_ID.ordinal,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
)
}
}

override fun onDestroy() {
Expand Down
15 changes: 9 additions & 6 deletions app/src/main/kotlin/com/wire/android/services/ServicesManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

package com.wire.android.services

import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
Expand All @@ -34,7 +33,6 @@ import kotlinx.coroutines.launch
import org.jetbrains.annotations.VisibleForTesting
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.reflect.KClass

/**
* This is helper class that should be used for starting/stopping any services.
Expand Down Expand Up @@ -102,11 +100,15 @@ class ServicesManager @Inject constructor(

// Persistent WebSocket
fun startPersistentWebSocketService() {
startService(PersistentWebSocketService.newIntent(context))
if (PersistentWebSocketService.isServiceStarted) {
appLogger.i("ServicesManager: PersistentWebsocketService already started, not starting again")
} else {
startService(PersistentWebSocketService.newIntent(context))
}
}

fun stopPersistentWebSocketService() {
stopService(PersistentWebSocketService::class)
stopService(PersistentWebSocketService.newIntent(context))
}

fun isPersistentWebSocketServiceRunning(): Boolean =
Expand All @@ -121,8 +123,9 @@ class ServicesManager @Inject constructor(
}
}

private fun stopService(serviceClass: KClass<out Service>) {
context.stopService(Intent(context, serviceClass.java))
private fun stopService(intent: Intent) {
appLogger.i("ServicesManager: stopping service for $intent")
context.stopService(intent)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
*/
package com.wire.android.feature

import android.content.ComponentName
import android.content.Context
import com.wire.android.services.ServicesManager
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.every
Expand All @@ -41,7 +40,7 @@ class StartPersistentWebsocketIfNecessaryUseCaseTest {
sut.invoke()

// then
verify(exactly = 1) { arrangement.applicationContext.startService(any()) }
verify(exactly = 1) { arrangement.servicesManager.startPersistentWebSocketService() }
}

@Test
Expand All @@ -56,7 +55,7 @@ class StartPersistentWebsocketIfNecessaryUseCaseTest {
sut.invoke()

// then
verify(exactly = 0) { arrangement.applicationContext.startService(any()) }
verify(exactly = 0) { arrangement.servicesManager.startPersistentWebSocketService() }
}

inner class Arrangement {
Expand All @@ -65,16 +64,16 @@ class StartPersistentWebsocketIfNecessaryUseCaseTest {
lateinit var shouldStartPersistentWebSocketServiceUseCase: ShouldStartPersistentWebSocketServiceUseCase

@MockK
lateinit var applicationContext: Context
lateinit var servicesManager: ServicesManager

init {
MockKAnnotations.init(this, relaxUnitFun = true)
every { applicationContext.startService(any()) } returns ComponentName.createRelative("dummy", "class")
every { applicationContext.stopService(any()) } returns true
every { servicesManager.startPersistentWebSocketService() } returns Unit
every { servicesManager.stopPersistentWebSocketService() } returns Unit
}

fun arrange() = this to StartPersistentWebsocketIfNecessaryUseCase(
applicationContext,
servicesManager,
shouldStartPersistentWebSocketServiceUseCase
)

Expand Down
Loading