mirror of
https://github.com/afollestad/nock-nock.git
synced 2025-08-10 09:58:44 +00:00
Fix StatusUpdateIntentReceiverTest
This commit is contained in:
parent
1e92644904
commit
98327c8c5b
8 changed files with 72 additions and 27 deletions
|
@ -15,11 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock.broadcasts
|
package com.afollestad.nocknock.broadcasts
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
|
||||||
import androidx.lifecycle.Lifecycle.Event.ON_PAUSE
|
import androidx.lifecycle.Lifecycle.Event.ON_PAUSE
|
||||||
import androidx.lifecycle.Lifecycle.Event.ON_RESUME
|
import androidx.lifecycle.Lifecycle.Event.ON_RESUME
|
||||||
import androidx.lifecycle.LifecycleObserver
|
import androidx.lifecycle.LifecycleObserver
|
||||||
|
@ -27,13 +26,15 @@ import androidx.lifecycle.OnLifecycleEvent
|
||||||
import com.afollestad.nocknock.data.model.Site
|
import com.afollestad.nocknock.data.model.Site
|
||||||
import com.afollestad.nocknock.engine.validation.ValidationJob.Companion.ACTION_STATUS_UPDATE
|
import com.afollestad.nocknock.engine.validation.ValidationJob.Companion.ACTION_STATUS_UPDATE
|
||||||
import com.afollestad.nocknock.engine.validation.ValidationJob.Companion.KEY_UPDATE_MODEL
|
import com.afollestad.nocknock.engine.validation.ValidationJob.Companion.KEY_UPDATE_MODEL
|
||||||
|
import com.afollestad.nocknock.utilities.providers.IntentProvider
|
||||||
|
|
||||||
typealias SiteCallback = (Site) -> Unit
|
typealias SiteCallback = (Site) -> Unit
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class StatusUpdateIntentReceiver(
|
class StatusUpdateIntentReceiver(
|
||||||
private val app: Application,
|
private val context: Context,
|
||||||
private val callback: SiteCallback
|
private val intentProvider: IntentProvider,
|
||||||
|
private var callback: SiteCallback?
|
||||||
) : LifecycleObserver {
|
) : LifecycleObserver {
|
||||||
|
|
||||||
internal val intentReceiver = object : BroadcastReceiver() {
|
internal val intentReceiver = object : BroadcastReceiver() {
|
||||||
|
@ -44,19 +45,24 @@ class StatusUpdateIntentReceiver(
|
||||||
if (intent.action == ACTION_STATUS_UPDATE) {
|
if (intent.action == ACTION_STATUS_UPDATE) {
|
||||||
val model = intent.getSerializableExtra(KEY_UPDATE_MODEL) as? Site
|
val model = intent.getSerializableExtra(KEY_UPDATE_MODEL) as? Site
|
||||||
?: return
|
?: return
|
||||||
callback(model)
|
callback?.invoke(model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnLifecycleEvent(ON_RESUME)
|
@OnLifecycleEvent(ON_RESUME)
|
||||||
fun onResume() {
|
fun onResume() {
|
||||||
val filter = IntentFilter().apply {
|
val filter = intentProvider.createFilter(ACTION_STATUS_UPDATE)
|
||||||
addAction(ACTION_STATUS_UPDATE)
|
context.registerReceiver(intentReceiver, filter)
|
||||||
}
|
|
||||||
app.registerReceiver(intentReceiver, filter)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnLifecycleEvent(ON_PAUSE)
|
@OnLifecycleEvent(ON_PAUSE)
|
||||||
fun onPause() = app.unregisterReceiver(intentReceiver)
|
fun onPause() {
|
||||||
|
context.unregisterReceiver(intentReceiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnLifecycleEvent(ON_DESTROY)
|
||||||
|
fun onDestroy() {
|
||||||
|
callback = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import com.afollestad.nocknock.broadcasts.StatusUpdateIntentReceiver
|
||||||
import com.afollestad.nocknock.data.model.Site
|
import com.afollestad.nocknock.data.model.Site
|
||||||
import com.afollestad.nocknock.dialogs.AboutDialog
|
import com.afollestad.nocknock.dialogs.AboutDialog
|
||||||
import com.afollestad.nocknock.notifications.NockNotificationManager
|
import com.afollestad.nocknock.notifications.NockNotificationManager
|
||||||
|
import com.afollestad.nocknock.utilities.providers.IntentProvider
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.showOrHide
|
import com.afollestad.nocknock.viewcomponents.ext.showOrHide
|
||||||
import kotlinx.android.synthetic.main.activity_main.fab
|
import kotlinx.android.synthetic.main.activity_main.fab
|
||||||
import kotlinx.android.synthetic.main.activity_main.list
|
import kotlinx.android.synthetic.main.activity_main.list
|
||||||
|
@ -43,12 +44,14 @@ import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private val notificationManager by inject<NockNotificationManager>()
|
private val notificationManager by inject<NockNotificationManager>()
|
||||||
|
private val intentProvider by inject<IntentProvider>()
|
||||||
|
|
||||||
internal val viewModel by viewModel<MainViewModel>()
|
internal val viewModel by viewModel<MainViewModel>()
|
||||||
|
|
||||||
private lateinit var adapter: ServerAdapter
|
private lateinit var adapter: ServerAdapter
|
||||||
|
|
||||||
private val statusUpdateReceiver =
|
private val statusUpdateReceiver =
|
||||||
StatusUpdateIntentReceiver(application) {
|
StatusUpdateIntentReceiver(application, intentProvider) {
|
||||||
viewModel.postSiteUpdate(it)
|
viewModel.postSiteUpdate(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import com.afollestad.nocknock.R
|
||||||
import com.afollestad.nocknock.broadcasts.StatusUpdateIntentReceiver
|
import com.afollestad.nocknock.broadcasts.StatusUpdateIntentReceiver
|
||||||
import com.afollestad.nocknock.data.model.Site
|
import com.afollestad.nocknock.data.model.Site
|
||||||
import com.afollestad.nocknock.data.model.ValidationMode
|
import com.afollestad.nocknock.data.model.ValidationMode
|
||||||
|
import com.afollestad.nocknock.utilities.providers.IntentProvider
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.attachLiveData
|
import com.afollestad.nocknock.viewcomponents.ext.attachLiveData
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.dimenFloat
|
import com.afollestad.nocknock.viewcomponents.ext.dimenFloat
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.onScroll
|
import com.afollestad.nocknock.viewcomponents.ext.onScroll
|
||||||
|
@ -48,6 +49,7 @@ import kotlinx.android.synthetic.main.activity_viewsite.textNextCheck
|
||||||
import kotlinx.android.synthetic.main.activity_viewsite.textUrlWarning
|
import kotlinx.android.synthetic.main.activity_viewsite.textUrlWarning
|
||||||
import kotlinx.android.synthetic.main.activity_viewsite.toolbar
|
import kotlinx.android.synthetic.main.activity_viewsite.toolbar
|
||||||
import kotlinx.android.synthetic.main.activity_viewsite.validationModeDescription
|
import kotlinx.android.synthetic.main.activity_viewsite.validationModeDescription
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
|
@ -55,8 +57,9 @@ class ViewSiteActivity : AppCompatActivity() {
|
||||||
|
|
||||||
internal val viewModel by viewModel<ViewSiteViewModel>()
|
internal val viewModel by viewModel<ViewSiteViewModel>()
|
||||||
|
|
||||||
|
private val intentProvider by inject<IntentProvider>()
|
||||||
private val statusUpdateReceiver =
|
private val statusUpdateReceiver =
|
||||||
StatusUpdateIntentReceiver(application) {
|
StatusUpdateIntentReceiver(application, intentProvider) {
|
||||||
viewModel.setModel(it)
|
viewModel.setModel(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock
|
package com.afollestad.nocknock
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import com.afollestad.nocknock.data.AppDatabase
|
import com.afollestad.nocknock.data.AppDatabase
|
||||||
import com.afollestad.nocknock.data.SiteDao
|
import com.afollestad.nocknock.data.SiteDao
|
||||||
import com.afollestad.nocknock.data.SiteSettingsDao
|
import com.afollestad.nocknock.data.SiteSettingsDao
|
||||||
|
@ -27,6 +29,9 @@ import com.afollestad.nocknock.data.model.Status.OK
|
||||||
import com.afollestad.nocknock.data.model.ValidationMode
|
import com.afollestad.nocknock.data.model.ValidationMode
|
||||||
import com.afollestad.nocknock.data.model.ValidationMode.STATUS_CODE
|
import com.afollestad.nocknock.data.model.ValidationMode.STATUS_CODE
|
||||||
import com.afollestad.nocknock.data.model.ValidationResult
|
import com.afollestad.nocknock.data.model.ValidationResult
|
||||||
|
import com.afollestad.nocknock.utilities.providers.CanNotifyModel
|
||||||
|
import com.afollestad.nocknock.utilities.providers.IntentProvider
|
||||||
|
import com.nhaarman.mockitokotlin2.any
|
||||||
import com.nhaarman.mockitokotlin2.doAnswer
|
import com.nhaarman.mockitokotlin2.doAnswer
|
||||||
import com.nhaarman.mockitokotlin2.doReturn
|
import com.nhaarman.mockitokotlin2.doReturn
|
||||||
import com.nhaarman.mockitokotlin2.isA
|
import com.nhaarman.mockitokotlin2.isA
|
||||||
|
@ -130,3 +135,21 @@ fun mockDatabase(): AppDatabase {
|
||||||
on { validationResultsDao() } doReturn resultsDao
|
on { validationResultsDao() } doReturn resultsDao
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun mockIntentProvider() = object : IntentProvider {
|
||||||
|
override fun createFilter(vararg actions: String): IntentFilter {
|
||||||
|
return mock {
|
||||||
|
on { this.getAction(any()) } doAnswer { inv ->
|
||||||
|
val index = inv.getArgument<Int>(0)
|
||||||
|
return@doAnswer actions[index]
|
||||||
|
}
|
||||||
|
on { this.actionsIterator() } doReturn actions.iterator()
|
||||||
|
on { this.countActions() } doReturn actions.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPendingIntentForViewSite(model: CanNotifyModel): PendingIntent {
|
||||||
|
// basically no-op right now
|
||||||
|
return mock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,9 +21,11 @@ import com.afollestad.nocknock.MOCK_MODEL_2
|
||||||
import com.afollestad.nocknock.engine.validation.ValidationJob.Companion.ACTION_STATUS_UPDATE
|
import com.afollestad.nocknock.engine.validation.ValidationJob.Companion.ACTION_STATUS_UPDATE
|
||||||
import com.afollestad.nocknock.engine.validation.ValidationJob.Companion.KEY_UPDATE_MODEL
|
import com.afollestad.nocknock.engine.validation.ValidationJob.Companion.KEY_UPDATE_MODEL
|
||||||
import com.afollestad.nocknock.fakeIntent
|
import com.afollestad.nocknock.fakeIntent
|
||||||
|
import com.afollestad.nocknock.mockIntentProvider
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import com.nhaarman.mockitokotlin2.argumentCaptor
|
import com.nhaarman.mockitokotlin2.argumentCaptor
|
||||||
import com.nhaarman.mockitokotlin2.doReturn
|
import com.nhaarman.mockitokotlin2.doReturn
|
||||||
|
import com.nhaarman.mockitokotlin2.eq
|
||||||
import com.nhaarman.mockitokotlin2.mock
|
import com.nhaarman.mockitokotlin2.mock
|
||||||
import com.nhaarman.mockitokotlin2.times
|
import com.nhaarman.mockitokotlin2.times
|
||||||
import com.nhaarman.mockitokotlin2.verify
|
import com.nhaarman.mockitokotlin2.verify
|
||||||
|
@ -34,9 +36,10 @@ import org.junit.Test
|
||||||
class StatusUpdateIntentReceiverTest {
|
class StatusUpdateIntentReceiverTest {
|
||||||
|
|
||||||
private val app = mock<Application>()
|
private val app = mock<Application>()
|
||||||
|
private val intentProvider = mockIntentProvider()
|
||||||
private val callback = mock<SiteCallback>()
|
private val callback = mock<SiteCallback>()
|
||||||
|
|
||||||
private val receiver = StatusUpdateIntentReceiver(app, callback)
|
private val receiver = StatusUpdateIntentReceiver(app, intentProvider, callback)
|
||||||
|
|
||||||
@Test fun onReceive() {
|
@Test fun onReceive() {
|
||||||
val badIntent = fakeIntent("Hello World")
|
val badIntent = fakeIntent("Hello World")
|
||||||
|
@ -54,7 +57,7 @@ class StatusUpdateIntentReceiverTest {
|
||||||
receiver.onResume()
|
receiver.onResume()
|
||||||
|
|
||||||
val filterCaptor = argumentCaptor<IntentFilter>()
|
val filterCaptor = argumentCaptor<IntentFilter>()
|
||||||
verify(app).registerReceiver(receiver.intentReceiver, filterCaptor.capture())
|
verify(app).registerReceiver(eq(receiver.intentReceiver), filterCaptor.capture())
|
||||||
|
|
||||||
val actionIterator = filterCaptor.firstValue.actionsIterator()
|
val actionIterator = filterCaptor.firstValue.actionsIterator()
|
||||||
assertThat(actionIterator.hasNext()).isTrue()
|
assertThat(actionIterator.hasNext()).isTrue()
|
||||||
|
|
|
@ -19,21 +19,24 @@ import android.app.PendingIntent
|
||||||
import android.app.PendingIntent.FLAG_CANCEL_CURRENT
|
import android.app.PendingIntent.FLAG_CANCEL_CURRENT
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
interface CanNotifyModel : Serializable {
|
interface CanNotifyModel : Serializable {
|
||||||
|
|
||||||
fun notiId(): Int
|
fun notifyId(): Int
|
||||||
|
|
||||||
fun notiName(): String
|
fun notifyName(): String
|
||||||
|
|
||||||
fun notiTag(): String
|
fun notifyTag(): String
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
interface IntentProvider {
|
interface IntentProvider {
|
||||||
|
|
||||||
|
fun createFilter(vararg actions: String): IntentFilter
|
||||||
|
|
||||||
fun getPendingIntentForViewSite(
|
fun getPendingIntentForViewSite(
|
||||||
model: CanNotifyModel
|
model: CanNotifyModel
|
||||||
): PendingIntent
|
): PendingIntent
|
||||||
|
@ -50,11 +53,15 @@ class RealIntentProvider(
|
||||||
const val KEY_VIEW_NOTIFICATION_MODEL = "model"
|
const val KEY_VIEW_NOTIFICATION_MODEL = "model"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun createFilter(vararg actions: String) = IntentFilter().apply {
|
||||||
|
actions.forEach { addAction(it) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun getPendingIntentForViewSite(model: CanNotifyModel): PendingIntent {
|
override fun getPendingIntentForViewSite(model: CanNotifyModel): PendingIntent {
|
||||||
val openIntent = getIntentForViewSite(model)
|
val openIntent = getIntentForViewSite(model)
|
||||||
return PendingIntent.getActivity(
|
return PendingIntent.getActivity(
|
||||||
context,
|
context,
|
||||||
BASE_NOTIFICATION_REQUEST_CODE + model.notiId(),
|
BASE_NOTIFICATION_REQUEST_CODE + model.notifyId(),
|
||||||
openIntent,
|
openIntent,
|
||||||
FLAG_CANCEL_CURRENT
|
FLAG_CANCEL_CURRENT
|
||||||
)
|
)
|
||||||
|
|
|
@ -41,11 +41,11 @@ data class Site(
|
||||||
|
|
||||||
constructor() : this(0, "", "", null, null)
|
constructor() : this(0, "", "", null, null)
|
||||||
|
|
||||||
override fun notiId(): Int = id.toInt()
|
override fun notifyId(): Int = id.toInt()
|
||||||
|
|
||||||
override fun notiName(): String = name
|
override fun notifyName(): String = name
|
||||||
|
|
||||||
override fun notiTag(): String = url
|
override fun notifyTag(): String = url
|
||||||
|
|
||||||
fun intervalText(): String {
|
fun intervalText(): String {
|
||||||
requireNotNull(settings) { "Settings not queried." }
|
requireNotNull(settings) { "Settings not queried." }
|
||||||
|
|
|
@ -66,29 +66,29 @@ class RealNockNotificationManager(
|
||||||
override fun postStatusNotification(model: CanNotifyModel) {
|
override fun postStatusNotification(model: CanNotifyModel) {
|
||||||
if (isAppOpen) {
|
if (isAppOpen) {
|
||||||
// Don't show notifications while the app is open
|
// Don't show notifications while the app is open
|
||||||
log("App is open, status notification for site ${model.notiId()} won't be posted.")
|
log("App is open, status notification for site ${model.notifyId()} won't be posted.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log("Posting status notification for site ${model.notiId()}...")
|
log("Posting status notification for site ${model.notifyId()}...")
|
||||||
val intent = intentProvider.getPendingIntentForViewSite(model)
|
val intent = intentProvider.getPendingIntentForViewSite(model)
|
||||||
|
|
||||||
val newNotification = notificationProvider.create(
|
val newNotification = notificationProvider.create(
|
||||||
channelId = CheckFailures.id,
|
channelId = CheckFailures.id,
|
||||||
title = model.notiName(),
|
title = model.notifyName(),
|
||||||
content = stringProvider.get(R.string.something_wrong),
|
content = stringProvider.get(R.string.something_wrong),
|
||||||
intent = intent,
|
intent = intent,
|
||||||
smallIcon = R.drawable.ic_notification,
|
smallIcon = R.drawable.ic_notification,
|
||||||
largeIcon = bitmapProvider.get(appIconRes)
|
largeIcon = bitmapProvider.get(appIconRes)
|
||||||
)
|
)
|
||||||
|
|
||||||
stockManager.notify(model.notiTag(), model.notificationId(), newNotification)
|
stockManager.notify(model.notifyTag(), model.notificationId(), newNotification)
|
||||||
log("Posted status notification for site ${model.notificationId()}.")
|
log("Posted status notification for site ${model.notificationId()}.")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelStatusNotification(model: CanNotifyModel) {
|
override fun cancelStatusNotification(model: CanNotifyModel) {
|
||||||
stockManager.cancel(model.notificationId())
|
stockManager.cancel(model.notificationId())
|
||||||
log("Cancelled status notification for site ${model.notiId()}.")
|
log("Cancelled status notification for site ${model.notifyId()}.")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelStatusNotifications() = stockManager.cancelAll()
|
override fun cancelStatusNotifications() = stockManager.cancelAll()
|
||||||
|
@ -105,5 +105,5 @@ class RealNockNotificationManager(
|
||||||
log("Created notification channel ${channel.id}")
|
log("Created notification channel ${channel.id}")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CanNotifyModel.notificationId() = BASE_NOTIFICATION_REQUEST_CODE + this.notiId()
|
private fun CanNotifyModel.notificationId() = BASE_NOTIFICATION_REQUEST_CODE + this.notifyId()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue