mirror of
https://github.com/home-assistant/android
synced 2024-10-01 13:53:53 +00:00
Basic Notification Support (#140)
* Initial pass on notifications support * Linting and Dep updates. * Basic Notification Support complete. * Fix onboarding flow and test compile issue. * Fix unit tests * Bump tool versions. * All tests pass... Need to clean up still. * Using correct mockk features. * Using correct mockk features everywhere. * More test fixes.
This commit is contained in:
parent
b8a9737d18
commit
20cc710490
|
@ -94,6 +94,9 @@ dependencies {
|
|||
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
|
||||
|
||||
implementation 'com.google.android.gms:play-services-location:17.0.0'
|
||||
implementation "com.google.firebase:firebase-core:17.2.1"
|
||||
implementation "com.google.firebase:firebase-iid:20.0.2"
|
||||
implementation "com.google.firebase:firebase-messaging:20.1.0"
|
||||
|
||||
testImplementation "org.spekframework.spek2:spek-dsl-jvm:$spek2Version"
|
||||
testImplementation "org.spekframework.spek2:spek-runner-junit5:$spek2Version"
|
||||
|
|
|
@ -44,6 +44,20 @@
|
|||
<activity
|
||||
android:name=".settings.SettingsActivity"
|
||||
android:parentActivityName=".webview.WebViewActivity"/>
|
||||
<service
|
||||
android:name=".notifications.MessagingService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||
android:resource="@drawable/ic_launcher_foreground" />
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_color"
|
||||
android:resource="@color/colorPrimary" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
package io.homeassistant.companion.android.launch
|
||||
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import com.google.firebase.iid.FirebaseInstanceId
|
||||
import io.homeassistant.companion.android.BuildConfig
|
||||
import io.homeassistant.companion.android.domain.authentication.AuthenticationUseCase
|
||||
import io.homeassistant.companion.android.domain.authentication.SessionState
|
||||
import io.homeassistant.companion.android.domain.integration.IntegrationUseCase
|
||||
import io.homeassistant.companion.android.notifications.MessagingService
|
||||
import java.lang.Exception
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -11,14 +18,20 @@ import kotlinx.coroutines.launch
|
|||
|
||||
class LaunchPresenterImpl @Inject constructor(
|
||||
private val view: LaunchView,
|
||||
private val authenticationUseCase: AuthenticationUseCase
|
||||
private val authenticationUseCase: AuthenticationUseCase,
|
||||
private val integrationUseCase: IntegrationUseCase
|
||||
) : LaunchPresenter {
|
||||
|
||||
companion object {
|
||||
const val TAG = "LaunchPresenter"
|
||||
}
|
||||
|
||||
private val mainScope: CoroutineScope = CoroutineScope(Dispatchers.Main + Job())
|
||||
|
||||
override fun onViewReady() {
|
||||
mainScope.launch {
|
||||
if (authenticationUseCase.getSessionState() == SessionState.CONNECTED) {
|
||||
resyncNotificationIds()
|
||||
view.displayWebview()
|
||||
} else {
|
||||
view.displayOnBoarding()
|
||||
|
@ -29,4 +42,24 @@ class LaunchPresenterImpl @Inject constructor(
|
|||
override fun onFinish() {
|
||||
mainScope.cancel()
|
||||
}
|
||||
|
||||
// TODO: This should probably go in settings?
|
||||
private fun resyncNotificationIds() {
|
||||
FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener {
|
||||
mainScope.launch {
|
||||
try {
|
||||
integrationUseCase.updateRegistration(
|
||||
"${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})",
|
||||
Build.MODEL ?: "UNKNOWN",
|
||||
Build.MANUFACTURER ?: "UNKNOWN",
|
||||
Build.MODEL ?: "UNKNOWN",
|
||||
Build.VERSION.SDK_INT.toString(),
|
||||
MessagingService.generateAppData(it.token)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Issue updating Registration", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
package io.homeassistant.companion.android.notifications
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.RingtoneManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.google.firebase.messaging.FirebaseMessagingService
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
import io.homeassistant.companion.android.BuildConfig
|
||||
import io.homeassistant.companion.android.R
|
||||
import io.homeassistant.companion.android.common.dagger.GraphComponentAccessor
|
||||
import io.homeassistant.companion.android.domain.integration.IntegrationUseCase
|
||||
import io.homeassistant.companion.android.webview.WebViewActivity
|
||||
import java.lang.Exception
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MessagingService : FirebaseMessagingService() {
|
||||
companion object {
|
||||
const val TAG = "MessagingService"
|
||||
|
||||
fun generateAppData(pushToken: String): HashMap<String, String> {
|
||||
return hashMapOf(
|
||||
"push_url" to "https://mobile-apps.home-assistant.io/api/sendPushNotification",
|
||||
"push_token" to pushToken
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
lateinit var integrationUseCase: IntegrationUseCase
|
||||
|
||||
private val mainScope: CoroutineScope = CoroutineScope(Dispatchers.Main + Job())
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
DaggerServiceComponent.builder()
|
||||
.appComponent((applicationContext as GraphComponentAccessor).appComponent)
|
||||
.build()
|
||||
.inject(this)
|
||||
}
|
||||
|
||||
override fun onMessageReceived(remoteMessage: RemoteMessage) {
|
||||
Log.d(TAG, "From: ${remoteMessage.from}")
|
||||
|
||||
// Check if message contains a data payload.
|
||||
remoteMessage.data.isNotEmpty().let {
|
||||
Log.d(TAG, "Message data payload: " + remoteMessage.data)
|
||||
}
|
||||
|
||||
remoteMessage.notification?.let {
|
||||
Log.d(TAG, "Message Notification: ${it.title} -> ${it.body}")
|
||||
sendNotification(it.title, it.body!!)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and show a simple notification containing the received FCM message.
|
||||
*
|
||||
* @param messageBody FCM message body received.
|
||||
*/
|
||||
private fun sendNotification(messageTitle: String?, messageBody: String) {
|
||||
val intent = Intent(this, WebViewActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
val pendingIntent = PendingIntent.getActivity(this, 0, intent,
|
||||
PendingIntent.FLAG_ONE_SHOT)
|
||||
|
||||
// TODO: implement channels
|
||||
val channelId = "default"
|
||||
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
|
||||
val notificationBuilder = NotificationCompat.Builder(this, channelId)
|
||||
.setSmallIcon(R.drawable.ic_launcher_foreground)
|
||||
.setContentTitle(messageTitle)
|
||||
.setContentText(messageBody)
|
||||
.setAutoCancel(true)
|
||||
.setSound(defaultSoundUri)
|
||||
.setContentIntent(pendingIntent)
|
||||
|
||||
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
// Since android Oreo notification channel is needed.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel(channelId,
|
||||
"Default Channel",
|
||||
NotificationManager.IMPORTANCE_DEFAULT)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
// TODO: This message id probably isn't the best
|
||||
notificationManager.notify((messageBody + messageTitle).hashCode(), notificationBuilder.build())
|
||||
}
|
||||
|
||||
/**
|
||||
* Called if InstanceID token is updated. This may occur if the security of
|
||||
* the previous token had been compromised. Note that this is called when the InstanceID token
|
||||
* is initially generated so this is where you would retrieve the token.
|
||||
*/
|
||||
override fun onNewToken(token: String) {
|
||||
mainScope.launch {
|
||||
Log.d(TAG, "Refreshed token: $token")
|
||||
try {
|
||||
integrationUseCase.updateRegistration(
|
||||
"${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})",
|
||||
Build.MODEL ?: "UNKNOWN",
|
||||
Build.MANUFACTURER ?: "UNKNOWN",
|
||||
Build.MODEL ?: "UNKNOWN",
|
||||
Build.VERSION.SDK_INT.toString(),
|
||||
generateAppData(token)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
// TODO: Store for update later
|
||||
Log.e(TAG, "Issue updating token", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package io.homeassistant.companion.android.notifications
|
||||
|
||||
import dagger.Component
|
||||
import io.homeassistant.companion.android.common.dagger.AppComponent
|
||||
|
||||
@Component(dependencies = [AppComponent::class])
|
||||
interface ServiceComponent {
|
||||
|
||||
fun inject(service: MessagingService)
|
||||
}
|
|
@ -4,9 +4,11 @@ import android.app.Activity
|
|||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import com.google.firebase.iid.FirebaseInstanceId
|
||||
import io.homeassistant.companion.android.BuildConfig
|
||||
import io.homeassistant.companion.android.domain.integration.DeviceRegistration
|
||||
import io.homeassistant.companion.android.domain.integration.IntegrationUseCase
|
||||
import io.homeassistant.companion.android.notifications.MessagingService
|
||||
import io.homeassistant.companion.android.util.PermissionManager
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -29,28 +31,37 @@ class MobileAppIntegrationPresenterImpl @Inject constructor(
|
|||
override fun onRegistrationAttempt() {
|
||||
|
||||
view.showLoading()
|
||||
val instanceId = FirebaseInstanceId.getInstance().instanceId
|
||||
instanceId.addOnSuccessListener {
|
||||
mainScope.launch {
|
||||
val token = it.token
|
||||
|
||||
mainScope.launch {
|
||||
val deviceRegistration = DeviceRegistration(
|
||||
BuildConfig.APPLICATION_ID,
|
||||
"Home Assistant",
|
||||
"${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})",
|
||||
Build.MODEL ?: "UNKNOWN",
|
||||
Build.MANUFACTURER ?: "UNKNOWN",
|
||||
Build.MODEL ?: "UNKNOWN",
|
||||
"Android",
|
||||
Build.VERSION.SDK_INT.toString(),
|
||||
false,
|
||||
null
|
||||
)
|
||||
try {
|
||||
integrationUseCase.registerDevice(deviceRegistration)
|
||||
view.deviceRegistered()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error with registering application", e)
|
||||
view.showError()
|
||||
val deviceRegistration = DeviceRegistration(
|
||||
BuildConfig.APPLICATION_ID,
|
||||
"Home Assistant",
|
||||
"${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})",
|
||||
Build.MODEL ?: "UNKNOWN",
|
||||
Build.MANUFACTURER ?: "UNKNOWN",
|
||||
Build.MODEL ?: "UNKNOWN",
|
||||
"Android",
|
||||
Build.VERSION.SDK_INT.toString(),
|
||||
false,
|
||||
token.let { MessagingService.generateAppData(it) }
|
||||
)
|
||||
|
||||
try {
|
||||
integrationUseCase.registerDevice(deviceRegistration)
|
||||
view.deviceRegistered()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error with registering application", e)
|
||||
view.showError()
|
||||
}
|
||||
}
|
||||
}
|
||||
instanceId.addOnFailureListener {
|
||||
Log.e(TAG, "Couldn't get FirebaseInstanceId", it)
|
||||
view.showError()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGrantedLocationPermission(context: Context, activity: Activity) {
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
package io.homeassistant.companion.android.launch
|
||||
|
||||
import com.google.android.gms.tasks.OnSuccessListener
|
||||
import com.google.firebase.iid.FirebaseInstanceId
|
||||
import com.google.firebase.iid.InstanceIdResult
|
||||
import io.homeassistant.companion.android.domain.authentication.AuthenticationUseCase
|
||||
import io.homeassistant.companion.android.domain.authentication.SessionState
|
||||
import io.homeassistant.companion.android.domain.integration.IntegrationUseCase
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.slot
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
|
@ -15,6 +22,27 @@ object LaunchPresenterImplSpec : Spek({
|
|||
|
||||
beforeEachTest {
|
||||
Dispatchers.setMain(Dispatchers.Unconfined)
|
||||
|
||||
val onSuccessListener = slot<OnSuccessListener<InstanceIdResult>>()
|
||||
val mockResults = mockk<InstanceIdResult> {
|
||||
every { token } returns "ABC123"
|
||||
}
|
||||
|
||||
mockkStatic(FirebaseInstanceId::class)
|
||||
every { FirebaseInstanceId.getInstance() } returns mockk {
|
||||
every { instanceId } returns mockk {
|
||||
every { addOnSuccessListener(capture(onSuccessListener)) } answers {
|
||||
onSuccessListener.captured.onSuccess(mockResults)
|
||||
|
||||
mockk {
|
||||
every { result } returns mockResults
|
||||
}
|
||||
}
|
||||
every { addOnFailureListener(any()) } returns mockk {
|
||||
every { exception } returns Exception()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterEachTest {
|
||||
|
@ -23,8 +51,9 @@ object LaunchPresenterImplSpec : Spek({
|
|||
|
||||
describe("launch presenter") {
|
||||
val authenticationUseCase by memoized { mockk<AuthenticationUseCase>() }
|
||||
val integrationUseCase by memoized { mockk<IntegrationUseCase>() }
|
||||
val view by memoized { mockk<LaunchView>(relaxUnitFun = true) }
|
||||
val presenter by memoized { LaunchPresenterImpl(view, authenticationUseCase) }
|
||||
val presenter by memoized { LaunchPresenterImpl(view, authenticationUseCase, integrationUseCase) }
|
||||
|
||||
describe("anonymous state") {
|
||||
beforeEachTest {
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
package io.homeassistant.companion.android.onboarding.integration
|
||||
|
||||
import android.os.Build
|
||||
import com.google.android.gms.tasks.OnSuccessListener
|
||||
import com.google.firebase.iid.FirebaseInstanceId
|
||||
import com.google.firebase.iid.InstanceIdResult
|
||||
import io.homeassistant.companion.android.BuildConfig
|
||||
import io.homeassistant.companion.android.domain.integration.DeviceRegistration
|
||||
import io.homeassistant.companion.android.domain.integration.IntegrationUseCase
|
||||
import io.homeassistant.companion.android.notifications.MessagingService
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.coVerifyAll
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.runs
|
||||
import io.mockk.slot
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.setMain
|
||||
|
@ -20,6 +27,27 @@ object MobileAppIntegrationPresenterImplSpec : Spek({
|
|||
|
||||
beforeEachTest {
|
||||
Dispatchers.setMain(Dispatchers.Unconfined)
|
||||
|
||||
val onSuccessListener = slot<OnSuccessListener<InstanceIdResult>>()
|
||||
val mockResults = mockk<InstanceIdResult> {
|
||||
every { token } returns "ABC123"
|
||||
}
|
||||
|
||||
mockkStatic(FirebaseInstanceId::class)
|
||||
every { FirebaseInstanceId.getInstance() } returns mockk {
|
||||
every { instanceId } returns mockk {
|
||||
every { addOnSuccessListener(capture(onSuccessListener)) } answers {
|
||||
onSuccessListener.captured.onSuccess(mockResults)
|
||||
|
||||
mockk {
|
||||
every { result } returns mockResults
|
||||
}
|
||||
}
|
||||
every { addOnFailureListener(any()) } returns mockk {
|
||||
every { exception } returns Exception()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterEachTest {
|
||||
|
@ -52,7 +80,7 @@ object MobileAppIntegrationPresenterImplSpec : Spek({
|
|||
"Android",
|
||||
Build.VERSION.SDK_INT.toString(),
|
||||
false,
|
||||
null
|
||||
MessagingService.generateAppData("ABC123")
|
||||
)
|
||||
beforeEachTest {
|
||||
coEvery { integrationUseCase.registerDevice(deviceRegistration) } just runs
|
||||
|
|
|
@ -9,9 +9,9 @@ buildscript {
|
|||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.2'
|
||||
classpath 'com.android.tools.build:gradle:3.5.3'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath 'com.google.gms:google-services:4.3.2'
|
||||
classpath 'com.google.gms:google-services:4.3.3'
|
||||
classpath 'io.fabric.tools:gradle:1.31.2'
|
||||
classpath "org.jlleitschuh.gradle:ktlint-gradle:9.1.1"
|
||||
}
|
||||
|
|
|
@ -34,7 +34,25 @@ class IntegrationRepositoryImpl @Inject constructor(
|
|||
authenticationRepository.buildBearerToken(),
|
||||
createRegisterDeviceRequest(deviceRegistration)
|
||||
)
|
||||
persistDeviceRegistrationResponse(response)
|
||||
}
|
||||
|
||||
override suspend fun updateRegistration(deviceRegistration: DeviceRegistration) {
|
||||
val request = IntegrationRequest("update_registration", createRegisterDeviceRequest(deviceRegistration))
|
||||
for (it in getUrls()) {
|
||||
try {
|
||||
if (integrationService.updateRegistration(it, request).isSuccessful) {
|
||||
return
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// Ignore failure until we are out of URLS to try!
|
||||
}
|
||||
}
|
||||
|
||||
throw IntegrationException()
|
||||
}
|
||||
|
||||
private suspend fun persistDeviceRegistrationResponse(response: RegisterDeviceResponse) {
|
||||
localStorage.putString(PREF_CLOUD_URL, response.cloudhookUrl)
|
||||
localStorage.putString(PREF_REMOTE_UI_URL, response.remoteUiUrl)
|
||||
localStorage.putString(PREF_SECRET, response.secret)
|
||||
|
|
|
@ -17,6 +17,12 @@ interface IntegrationService {
|
|||
@Body request: RegisterDeviceRequest
|
||||
): RegisterDeviceResponse
|
||||
|
||||
@POST
|
||||
suspend fun updateRegistration(
|
||||
@Url url: HttpUrl,
|
||||
@Body request: IntegrationRequest
|
||||
): Response<ResponseBody>
|
||||
|
||||
@POST
|
||||
suspend fun updateLocation(
|
||||
@Url url: HttpUrl,
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
package io.homeassistant.companion.android.data.integration
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude
|
||||
import java.util.Dictionary
|
||||
import java.util.Objects
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
data class RegisterDeviceRequest(
|
||||
var appId: String,
|
||||
var appName: String,
|
||||
var appVersion: String,
|
||||
var deviceName: String,
|
||||
var manufacturer: String,
|
||||
var model: String,
|
||||
var osName: String,
|
||||
var osVersion: String,
|
||||
var supportsEncryption: Boolean,
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
var appData: Dictionary<String, Objects>?
|
||||
var appId: String?,
|
||||
var appName: String?,
|
||||
var appVersion: String?,
|
||||
var deviceName: String?,
|
||||
var manufacturer: String?,
|
||||
var model: String?,
|
||||
var osName: String?,
|
||||
var osVersion: String?,
|
||||
var supportsEncryption: Boolean?,
|
||||
var appData: HashMap<String, String>?
|
||||
)
|
||||
|
|
|
@ -91,6 +91,55 @@ object IntegrationRepositoryImplSpec : Spek({
|
|||
}
|
||||
}
|
||||
|
||||
describe("registerDevice") {
|
||||
val deviceRegistration = DeviceRegistration(
|
||||
"appId",
|
||||
"appName",
|
||||
"appVersion",
|
||||
"deviceName",
|
||||
"manufacturer",
|
||||
"model",
|
||||
"osName",
|
||||
"osVersion",
|
||||
false,
|
||||
null
|
||||
)
|
||||
val registerDeviceRequest = RegisterDeviceRequest(
|
||||
deviceRegistration.appId,
|
||||
deviceRegistration.appName,
|
||||
deviceRegistration.appVersion,
|
||||
deviceRegistration.deviceName,
|
||||
deviceRegistration.manufacturer,
|
||||
deviceRegistration.model,
|
||||
deviceRegistration.osName,
|
||||
deviceRegistration.osVersion,
|
||||
deviceRegistration.supportsEncryption,
|
||||
deviceRegistration.appData
|
||||
)
|
||||
beforeEachTest {
|
||||
coEvery {
|
||||
integrationService.updateRegistration(any(), IntegrationRequest("update_registration", registerDeviceRequest))
|
||||
} returns Response.success(null)
|
||||
|
||||
coEvery { authenticationRepository.getUrl() } returns URL("http://example.com")
|
||||
coEvery { localStorage.getString("webhook_id") } returns "FGHIJ"
|
||||
coEvery { localStorage.getString("cloud_url") } returns "http://best.com/hook/id"
|
||||
coEvery { localStorage.getString("remote_ui_url") } returns "http://better.com"
|
||||
|
||||
runBlocking {
|
||||
repository.updateRegistration(deviceRegistration)
|
||||
}
|
||||
}
|
||||
|
||||
it("should call the service") {
|
||||
coVerify {
|
||||
integrationService.updateRegistration(
|
||||
"http://best.com/hook/id".toHttpUrl(),
|
||||
IntegrationRequest("update_registration", registerDeviceRequest))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe("is registered") {
|
||||
beforeEachTest {
|
||||
coEvery { localStorage.getString("webhook_id") } returns "FGHIJ"
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
package io.homeassistant.companion.android.domain.integration
|
||||
|
||||
import java.util.Dictionary
|
||||
import java.util.Objects
|
||||
|
||||
data class DeviceRegistration(
|
||||
val appId: String,
|
||||
val appName: String,
|
||||
val appVersion: String,
|
||||
val deviceName: String,
|
||||
val manufacturer: String,
|
||||
val model: String,
|
||||
val osName: String,
|
||||
val osVersion: String,
|
||||
val supportsEncryption: Boolean,
|
||||
val appData: Dictionary<String, Objects>?
|
||||
val appId: String? = null,
|
||||
val appName: String? = null,
|
||||
val appVersion: String? = null,
|
||||
val deviceName: String? = null,
|
||||
val manufacturer: String? = null,
|
||||
val model: String? = null,
|
||||
val osName: String? = null,
|
||||
val osVersion: String? = null,
|
||||
val supportsEncryption: Boolean? = null,
|
||||
val appData: HashMap<String, String>? = null
|
||||
)
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.homeassistant.companion.android.domain.integration
|
|||
interface IntegrationRepository {
|
||||
|
||||
suspend fun registerDevice(deviceRegistration: DeviceRegistration)
|
||||
suspend fun updateRegistration(deviceRegistration: DeviceRegistration)
|
||||
|
||||
suspend fun isRegistered(): Boolean
|
||||
|
||||
|
|
|
@ -3,6 +3,14 @@ package io.homeassistant.companion.android.domain.integration
|
|||
interface IntegrationUseCase {
|
||||
|
||||
suspend fun registerDevice(deviceRegistration: DeviceRegistration)
|
||||
suspend fun updateRegistration(
|
||||
appVersion: String,
|
||||
deviceName: String,
|
||||
manufacturer: String,
|
||||
model: String,
|
||||
osVersion: String,
|
||||
appData: HashMap<String, String>
|
||||
)
|
||||
|
||||
suspend fun isRegistered(): Boolean
|
||||
|
||||
|
@ -11,10 +19,8 @@ interface IntegrationUseCase {
|
|||
suspend fun getZones(): Array<Entity<ZoneAttributes>>
|
||||
|
||||
suspend fun setZoneTrackingEnabled(enabled: Boolean)
|
||||
|
||||
suspend fun isZoneTrackingEnabled(): Boolean
|
||||
|
||||
suspend fun setBackgroundTrackingEnabled(enabled: Boolean)
|
||||
|
||||
suspend fun isBackgroundTrackingEnabled(): Boolean
|
||||
}
|
||||
|
|
|
@ -9,6 +9,31 @@ class IntegrationUseCaseImpl @Inject constructor(
|
|||
integrationRepository.registerDevice(deviceRegistration)
|
||||
}
|
||||
|
||||
override suspend fun updateRegistration(
|
||||
appVersion: String,
|
||||
deviceName: String,
|
||||
manufacturer: String,
|
||||
model: String,
|
||||
osVersion: String,
|
||||
appData: HashMap<String, String>
|
||||
) {
|
||||
|
||||
integrationRepository.updateRegistration(
|
||||
DeviceRegistration(
|
||||
null,
|
||||
null,
|
||||
appVersion,
|
||||
deviceName,
|
||||
manufacturer,
|
||||
model,
|
||||
null,
|
||||
osVersion,
|
||||
null,
|
||||
appData
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun isRegistered(): Boolean {
|
||||
return integrationRepository.isRegistered()
|
||||
}
|
||||
|
|
|
@ -39,6 +39,34 @@ object IntegrationUseCaseImplSpec : Spek({
|
|||
}
|
||||
}
|
||||
|
||||
describe("updateRegistration") {
|
||||
beforeEachTest {
|
||||
coEvery {
|
||||
integrationRepository.updateRegistration(any())
|
||||
} just Runs
|
||||
|
||||
runBlocking {
|
||||
useCase.updateRegistration("1", "2", "3", "4", "5", hashMapOf())
|
||||
}
|
||||
}
|
||||
|
||||
it("should call repository") {
|
||||
coVerify {
|
||||
integrationRepository.updateRegistration(DeviceRegistration(
|
||||
null,
|
||||
null,
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
null,
|
||||
"5",
|
||||
null,
|
||||
hashMapOf()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe("isRegistered") {
|
||||
beforeEachTest {
|
||||
runBlocking { useCase.isRegistered() }
|
||||
|
|
Loading…
Reference in a new issue