mirror of
https://github.com/afollestad/nock-nock.git
synced 2025-04-20 03:25:14 +00:00
Unit tests for NockNotificationManager
This commit is contained in:
parent
cf39207c08
commit
03c687def5
21 changed files with 333 additions and 163 deletions
|
@ -35,6 +35,7 @@ dependencies {
|
|||
|
||||
implementation 'com.afollestad.material-dialogs:core:' + versions.materialDialogs
|
||||
|
||||
implementation 'com.jakewharton.timber:timber:' + versions.timber
|
||||
testImplementation 'junit:junit:' + versions.junit
|
||||
testImplementation 'org.mockito:mockito-core:' + versions.mockito
|
||||
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
package com.afollestad.nocknock
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import com.afollestad.nocknock.di.AppComponent
|
||||
import com.afollestad.nocknock.di.DaggerAppComponent
|
||||
import com.afollestad.nocknock.engine.statuscheck.BootReceiver
|
||||
|
@ -18,19 +17,14 @@ import com.afollestad.nocknock.ui.viewsite.ViewSiteActivity
|
|||
import com.afollestad.nocknock.utilities.Injector
|
||||
import com.afollestad.nocknock.utilities.ext.systemService
|
||||
import okhttp3.OkHttpClient
|
||||
import timber.log.Timber
|
||||
import timber.log.Timber.DebugTree
|
||||
import javax.inject.Inject
|
||||
import timber.log.Timber.d as log
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
class NockNockApp : Application(), Injector {
|
||||
|
||||
companion object {
|
||||
private fun log(message: String) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d("NockNockApp", message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var appComponent: AppComponent
|
||||
@Inject lateinit var nockNotificationManager: NockNotificationManager
|
||||
|
||||
|
@ -39,6 +33,10 @@ class NockNockApp : Application(), Injector {
|
|||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(DebugTree())
|
||||
}
|
||||
|
||||
val okHttpClient = OkHttpClient.Builder()
|
||||
.addNetworkInterceptor { chain ->
|
||||
val request = chain.request()
|
||||
|
|
|
@ -22,6 +22,7 @@ ext.versions = [
|
|||
materialDialogs : '2.0.0-rc3',
|
||||
rxkPrefs : '1.2.0',
|
||||
|
||||
timber : '4.7.1',
|
||||
junit : '4.12',
|
||||
mockito : '2.23.0',
|
||||
mockitoKotlin : '2.0.0-RC1',
|
||||
|
|
|
@ -27,6 +27,7 @@ dependencies {
|
|||
implementation 'com.google.dagger:dagger:' + versions.dagger
|
||||
kapt 'com.google.dagger:dagger-compiler:' + versions.dagger
|
||||
|
||||
implementation 'com.jakewharton.timber:timber:' + versions.timber
|
||||
testImplementation 'junit:junit:' + versions.junit
|
||||
testImplementation 'org.mockito:mockito-core:' + versions.mockito
|
||||
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin
|
||||
|
|
|
@ -7,13 +7,13 @@ package com.afollestad.nocknock.engine.db
|
|||
|
||||
import android.app.Application
|
||||
import android.database.Cursor
|
||||
import android.util.Log
|
||||
import com.afollestad.nocknock.data.ServerModel
|
||||
import com.afollestad.nocknock.data.ServerModel.Companion.COLUMN_ID
|
||||
import com.afollestad.nocknock.data.ServerModel.Companion.DEFAULT_SORT_ORDER
|
||||
import com.afollestad.nocknock.data.ServerModel.Companion.TABLE_NAME
|
||||
import com.afollestad.nocknock.engine.BuildConfig
|
||||
import com.afollestad.nocknock.utilities.ext.diffFrom
|
||||
import timber.log.Timber.d as log
|
||||
import timber.log.Timber.w as warn
|
||||
import javax.inject.Inject
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
|
@ -35,21 +35,6 @@ interface ServerModelStore {
|
|||
/** @author Aidan Follestad (@afollestad) */
|
||||
class RealServerModelStore @Inject constructor(app: Application) : ServerModelStore {
|
||||
|
||||
companion object {
|
||||
private fun log(
|
||||
message: String,
|
||||
warning: Boolean = false
|
||||
) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
if (warning) {
|
||||
Log.w("ServerModelStore", message)
|
||||
} else {
|
||||
Log.d("ServerModelStore", message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val dbHelper = ServerModelDbHelper(app)
|
||||
|
||||
override suspend fun get(id: Int?): List<ServerModel> {
|
||||
|
@ -115,7 +100,7 @@ class RealServerModelStore @Inject constructor(app: Application) : ServerModelSt
|
|||
val valuesDiff = oldValues.diffFrom(newValues)
|
||||
|
||||
if (valuesDiff.size() == 0) {
|
||||
log("Nothing has changed - nothing to update!", warning = true)
|
||||
warn("Nothing has changed - nothing to update!")
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,6 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.Intent.ACTION_BOOT_COMPLETED
|
||||
import android.util.Log
|
||||
import com.afollestad.nocknock.engine.BuildConfig
|
||||
import com.afollestad.nocknock.utilities.ext.injector
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
|
@ -18,18 +16,11 @@ import kotlinx.coroutines.GlobalScope
|
|||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import timber.log.Timber.d as log
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
class BootReceiver : BroadcastReceiver() {
|
||||
|
||||
companion object {
|
||||
private fun log(message: String) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d("BootReceiver", message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject lateinit var checkStatusManager: CheckStatusManager
|
||||
|
||||
override fun onReceive(
|
||||
|
|
|
@ -8,7 +8,6 @@ package com.afollestad.nocknock.engine.statuscheck
|
|||
import android.app.job.JobParameters
|
||||
import android.app.job.JobService
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.afollestad.nocknock.data.ServerModel
|
||||
import com.afollestad.nocknock.data.ServerStatus
|
||||
import com.afollestad.nocknock.data.ServerStatus.CHECKING
|
||||
|
@ -21,7 +20,6 @@ import com.afollestad.nocknock.data.isPending
|
|||
import com.afollestad.nocknock.engine.BuildConfig.APPLICATION_ID
|
||||
import com.afollestad.nocknock.engine.db.ServerModelStore
|
||||
import com.afollestad.nocknock.notifications.NockNotificationManager
|
||||
import com.afollestad.nocknock.utilities.BuildConfig
|
||||
import com.afollestad.nocknock.utilities.ext.injector
|
||||
import com.afollestad.nocknock.utilities.js.JavaScript
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
|
@ -32,6 +30,7 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.withContext
|
||||
import java.lang.System.currentTimeMillis
|
||||
import javax.inject.Inject
|
||||
import timber.log.Timber.d as log
|
||||
|
||||
/** @author Aidan Follestad (@afollestad)*/
|
||||
class CheckStatusJob : JobService() {
|
||||
|
@ -41,12 +40,6 @@ class CheckStatusJob : JobService() {
|
|||
const val ACTION_JOB_RUNNING = "$APPLICATION_ID.STATUS_JOB_RUNNING"
|
||||
const val KEY_UPDATE_MODEL = "site_model"
|
||||
const val KEY_SITE_ID = "site.id"
|
||||
|
||||
private fun log(message: String) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d("CheckStatusJob", message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject lateinit var modelStore: ServerModelStore
|
||||
|
|
|
@ -10,20 +10,19 @@ import android.app.job.JobInfo.NETWORK_TYPE_ANY
|
|||
import android.app.job.JobScheduler
|
||||
import android.app.job.JobScheduler.RESULT_SUCCESS
|
||||
import android.os.PersistableBundle
|
||||
import android.util.Log
|
||||
import com.afollestad.nocknock.data.ServerModel
|
||||
import com.afollestad.nocknock.data.ServerStatus.ERROR
|
||||
import com.afollestad.nocknock.data.ServerStatus.OK
|
||||
import com.afollestad.nocknock.engine.R
|
||||
import com.afollestad.nocknock.engine.db.ServerModelStore
|
||||
import com.afollestad.nocknock.engine.statuscheck.CheckStatusJob.Companion.KEY_SITE_ID
|
||||
import com.afollestad.nocknock.utilities.BuildConfig
|
||||
import com.afollestad.nocknock.utilities.providers.StringProvider
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import java.net.SocketTimeoutException
|
||||
import javax.inject.Inject
|
||||
import timber.log.Timber.d as log
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
data class CheckResult(
|
||||
|
@ -56,14 +55,6 @@ class RealCheckStatusManager @Inject constructor(
|
|||
private val siteStore: ServerModelStore
|
||||
) : CheckStatusManager {
|
||||
|
||||
companion object {
|
||||
private fun log(message: String) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d("CheckStatusManager", message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ensureScheduledChecks() {
|
||||
val sites = siteStore.get()
|
||||
if (sites.isEmpty()) {
|
||||
|
|
|
@ -26,6 +26,7 @@ dependencies {
|
|||
implementation 'com.google.dagger:dagger:' + versions.dagger
|
||||
kapt 'com.google.dagger:dagger-compiler:' + versions.dagger
|
||||
|
||||
implementation 'com.jakewharton.timber:timber:' + versions.timber
|
||||
testImplementation 'junit:junit:' + versions.junit
|
||||
testImplementation 'org.mockito:mockito-core:' + versions.mockito
|
||||
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin
|
||||
|
|
|
@ -5,10 +5,6 @@
|
|||
*/
|
||||
package com.afollestad.nocknock.notifications
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.content.Context
|
||||
import android.os.Build.VERSION_CODES
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.app.NotificationManagerCompat.IMPORTANCE_DEFAULT
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
|
@ -25,14 +21,3 @@ enum class Channel(
|
|||
importance = IMPORTANCE_DEFAULT
|
||||
)
|
||||
}
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
@RequiresApi(VERSION_CODES.O)
|
||||
fun Channel.toNotificationChannel(context: Context): NotificationChannel {
|
||||
val titleText = context.getString(this.title)
|
||||
val descriptionText = context.getString(this.description)
|
||||
return NotificationChannel(this.id, titleText, this.importance)
|
||||
.apply {
|
||||
description = descriptionText
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,20 +6,19 @@
|
|||
package com.afollestad.nocknock.notifications
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Application
|
||||
import android.app.NotificationManager
|
||||
import android.os.Build.VERSION_CODES
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat.DEFAULT_VIBRATE
|
||||
import com.afollestad.nocknock.data.ServerModel
|
||||
import com.afollestad.nocknock.notifications.Channel.CheckFailures
|
||||
import com.afollestad.nocknock.utilities.providers.BitmapProvider
|
||||
import com.afollestad.nocknock.utilities.providers.IntentProvider
|
||||
import com.afollestad.nocknock.utilities.providers.NotificationChannelProvider
|
||||
import com.afollestad.nocknock.utilities.providers.NotificationProvider
|
||||
import com.afollestad.nocknock.utilities.providers.RealIntentProvider.Companion.BASE_NOTIFICATION_REQUEST_CODE
|
||||
import com.afollestad.nocknock.utilities.providers.StringProvider
|
||||
import com.afollestad.nocknock.utilities.qualifiers.AppIconRes
|
||||
import com.afollestad.nocknock.utilities.util.hasOreo
|
||||
import javax.inject.Inject
|
||||
import timber.log.Timber.d as log
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
interface NockNotificationManager {
|
||||
|
@ -37,22 +36,15 @@ interface NockNotificationManager {
|
|||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
class RealNockNotificationManager @Inject constructor(
|
||||
private val app: Application,
|
||||
@AppIconRes private val appIconRes: Int,
|
||||
private val stockManager: NotificationManager,
|
||||
private val bitmapProvider: BitmapProvider,
|
||||
private val stringProvider: StringProvider,
|
||||
private val intentProvider: IntentProvider
|
||||
private val intentProvider: IntentProvider,
|
||||
private val channelProvider: NotificationChannelProvider,
|
||||
private val notificationProvider: NotificationProvider
|
||||
) : NockNotificationManager {
|
||||
|
||||
companion object {
|
||||
private fun log(message: String) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d("NockNotificationManager", message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var isAppOpen = false
|
||||
|
||||
override fun setIsAppOpen(open: Boolean) {
|
||||
|
@ -73,15 +65,14 @@ class RealNockNotificationManager @Inject constructor(
|
|||
log("Posting status notification for site ${model.id}...")
|
||||
val intent = intentProvider.getPendingIntentForViewSite(model)
|
||||
|
||||
val newNotification = notification(app, CheckFailures) {
|
||||
setContentTitle(model.name)
|
||||
setContentText(stringProvider.get(R.string.something_wrong))
|
||||
setContentIntent(intent)
|
||||
setSmallIcon(R.drawable.ic_notification)
|
||||
setLargeIcon(bitmapProvider.get(appIconRes))
|
||||
setAutoCancel(true)
|
||||
setDefaults(DEFAULT_VIBRATE)
|
||||
}
|
||||
val newNotification = notificationProvider.create(
|
||||
channelId = CheckFailures.id,
|
||||
title = model.name,
|
||||
content = stringProvider.get(R.string.something_wrong),
|
||||
intent = intent,
|
||||
smallIcon = R.drawable.ic_notification,
|
||||
largeIcon = bitmapProvider.get(appIconRes)
|
||||
)
|
||||
|
||||
stockManager.notify(model.url, model.notificationId(), newNotification)
|
||||
log("Posted status notification for site ${model.notificationId()}.")
|
||||
|
@ -96,13 +87,13 @@ class RealNockNotificationManager @Inject constructor(
|
|||
|
||||
@TargetApi(VERSION_CODES.O)
|
||||
private fun createChannel(channel: Channel) {
|
||||
if (!hasOreo()) {
|
||||
log("Not running Android O, channels won't be created.")
|
||||
return
|
||||
}
|
||||
|
||||
val notificationChannel = channel.toNotificationChannel(app)
|
||||
stockManager.createNotificationChannel(notificationChannel)
|
||||
val notificationChannel = channelProvider.create(
|
||||
id = channel.id,
|
||||
title = stringProvider.get(channel.title),
|
||||
description = stringProvider.get(channel.description),
|
||||
importance = channel.importance
|
||||
)
|
||||
notificationChannel?.let(stockManager::createNotificationChannel)
|
||||
log("Created notification channel ${channel.id}")
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* Licensed under Apache-2.0
|
||||
*
|
||||
* Designed and developed by Aidan Follestad (@afollestad)
|
||||
*/
|
||||
package com.afollestad.nocknock.notifications
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationCompat
|
||||
|
||||
typealias NotificationBuilder = NotificationCompat.Builder
|
||||
typealias NotificationConstructor = NotificationBuilder.() -> Unit
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
fun notification(
|
||||
context: Context,
|
||||
channel: Channel,
|
||||
builder: NotificationConstructor
|
||||
): Notification {
|
||||
val newNotification = NotificationCompat.Builder(context, channel.id)
|
||||
builder(newNotification)
|
||||
return newNotification.build()
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package com.afollestad.nocknock.notifications;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Licensed under Apache-2.0
|
||||
*
|
||||
* Designed and developed by Aidan Follestad (@afollestad)
|
||||
*/
|
||||
package com.afollestad.nocknock.notifications
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.graphics.Bitmap
|
||||
import com.afollestad.nocknock.data.ServerModel
|
||||
import com.afollestad.nocknock.data.ValidationMode.STATUS_CODE
|
||||
import com.afollestad.nocknock.notifications.Channel.CheckFailures
|
||||
import com.afollestad.nocknock.utilities.providers.BitmapProvider
|
||||
import com.afollestad.nocknock.utilities.providers.IntentProvider
|
||||
import com.afollestad.nocknock.utilities.providers.NotificationChannelProvider
|
||||
import com.afollestad.nocknock.utilities.providers.NotificationProvider
|
||||
import com.afollestad.nocknock.utilities.providers.RealIntentProvider.Companion.BASE_NOTIFICATION_REQUEST_CODE
|
||||
import com.afollestad.nocknock.utilities.providers.StringProvider
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.nhaarman.mockitokotlin2.any
|
||||
import com.nhaarman.mockitokotlin2.argumentCaptor
|
||||
import com.nhaarman.mockitokotlin2.doAnswer
|
||||
import com.nhaarman.mockitokotlin2.doReturn
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.times
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class NockNotificationManagerTest {
|
||||
|
||||
private val appIconRes = 1024
|
||||
private val somethingWentWrong = "something went wrong"
|
||||
|
||||
private val stockManager = mock<NotificationManager>()
|
||||
private val appIcon = mock<Bitmap>()
|
||||
private val bitmapProvider = mock<BitmapProvider> {
|
||||
on { get(appIconRes) } doReturn appIcon
|
||||
}
|
||||
private val stringProvider = mock<StringProvider> {
|
||||
on { get(R.string.something_wrong) } doReturn somethingWentWrong
|
||||
}
|
||||
private val intentProvider = mock<IntentProvider>()
|
||||
private val channelProvider = mock<NotificationChannelProvider>()
|
||||
private val notificationProvider = mock<NotificationProvider>()
|
||||
|
||||
private val manager = RealNockNotificationManager(
|
||||
appIconRes,
|
||||
stockManager,
|
||||
bitmapProvider,
|
||||
stringProvider,
|
||||
intentProvider,
|
||||
channelProvider,
|
||||
notificationProvider
|
||||
)
|
||||
|
||||
@Before fun setup() {
|
||||
whenever(channelProvider.create(any(), any(), any(), any())).doAnswer { inv ->
|
||||
val id = inv.getArgument<String>(0)
|
||||
val title = inv.getArgument<String>(1)
|
||||
val description = inv.getArgument<String>(2)
|
||||
val important = inv.getArgument<Int>(3)
|
||||
return@doAnswer mock<NotificationChannel> {
|
||||
on { this.id } doReturn id
|
||||
on { this.name } doReturn title
|
||||
on { this.description } doReturn description
|
||||
on { this.importance } doReturn important
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun createChannels() {
|
||||
whenever(stringProvider.get(any())).doReturn("")
|
||||
val createdChannel = mock<NotificationChannel> {
|
||||
on { this.id } doReturn CheckFailures.id
|
||||
}
|
||||
whenever(channelProvider.create(any(), any(), any(), any()))
|
||||
.doReturn(createdChannel)
|
||||
manager.createChannels()
|
||||
|
||||
val captor = argumentCaptor<NotificationChannel>()
|
||||
verify(stockManager, times(1)).createNotificationChannel(captor.capture())
|
||||
|
||||
val channel = captor.allValues.single()
|
||||
assertThat(channel.id).isEqualTo(CheckFailures.id)
|
||||
|
||||
verifyNoMoreInteractions(stockManager)
|
||||
}
|
||||
|
||||
@Test fun postStatusNotification_appIsOpen() {
|
||||
manager.setIsAppOpen(true)
|
||||
manager.postStatusNotification(fakeModel())
|
||||
|
||||
verifyNoMoreInteractions(stockManager)
|
||||
}
|
||||
|
||||
@Test fun postStatusNotification_appNotOpen() {
|
||||
manager.setIsAppOpen(false)
|
||||
val model = fakeModel()
|
||||
|
||||
val pendingIntent = mock<PendingIntent>()
|
||||
whenever(intentProvider.getPendingIntentForViewSite(model))
|
||||
.doReturn(pendingIntent)
|
||||
|
||||
val notification = mock<Notification>()
|
||||
whenever(
|
||||
notificationProvider.create(
|
||||
CheckFailures.id,
|
||||
model.name,
|
||||
somethingWentWrong,
|
||||
pendingIntent,
|
||||
R.drawable.ic_notification,
|
||||
appIcon
|
||||
)
|
||||
).doReturn(notification)
|
||||
|
||||
manager.postStatusNotification(model)
|
||||
|
||||
verify(stockManager).notify(
|
||||
model.url,
|
||||
BASE_NOTIFICATION_REQUEST_CODE + model.id,
|
||||
notification
|
||||
)
|
||||
verifyNoMoreInteractions(stockManager)
|
||||
}
|
||||
|
||||
@Test fun cancelStatusNotification() {
|
||||
val model = fakeModel()
|
||||
manager.cancelStatusNotification(model)
|
||||
verify(stockManager).cancel(BASE_NOTIFICATION_REQUEST_CODE + model.id)
|
||||
verifyNoMoreInteractions(stockManager)
|
||||
}
|
||||
|
||||
@Test fun cancelStatusNotifications() {
|
||||
manager.cancelStatusNotifications()
|
||||
verify(stockManager).cancelAll()
|
||||
verifyNoMoreInteractions(stockManager)
|
||||
}
|
||||
|
||||
private fun fakeModel() = ServerModel(
|
||||
id = 1,
|
||||
url = "https://hello.com",
|
||||
name = "Testing",
|
||||
validationMode = STATUS_CODE
|
||||
)
|
||||
}
|
|
@ -20,6 +20,7 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation 'androidx.annotation:annotation:' + versions.androidx
|
||||
implementation 'androidx.appcompat:appcompat:' + versions.androidx
|
||||
|
||||
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:' + versions.kotlin
|
||||
api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:' + versions.coroutines
|
||||
|
|
|
@ -7,9 +7,15 @@ package com.afollestad.nocknock.utilities
|
|||
|
||||
import com.afollestad.nocknock.utilities.providers.BitmapProvider
|
||||
import com.afollestad.nocknock.utilities.providers.IntentProvider
|
||||
import com.afollestad.nocknock.utilities.providers.NotificationChannelProvider
|
||||
import com.afollestad.nocknock.utilities.providers.NotificationProvider
|
||||
import com.afollestad.nocknock.utilities.providers.RealBitmapProvider
|
||||
import com.afollestad.nocknock.utilities.providers.RealIntentProvider
|
||||
import com.afollestad.nocknock.utilities.providers.RealNotificationChannelProvider
|
||||
import com.afollestad.nocknock.utilities.providers.RealNotificationProvider
|
||||
import com.afollestad.nocknock.utilities.providers.RealSdkProvider
|
||||
import com.afollestad.nocknock.utilities.providers.RealStringProvider
|
||||
import com.afollestad.nocknock.utilities.providers.SdkProvider
|
||||
import com.afollestad.nocknock.utilities.providers.StringProvider
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
@ -19,6 +25,12 @@ import javax.inject.Singleton
|
|||
@Module
|
||||
abstract class UtilitiesModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun provideSdkProvider(
|
||||
sdkProvider: RealSdkProvider
|
||||
): SdkProvider
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun provideBitmapProvider(
|
||||
|
@ -36,4 +48,16 @@ abstract class UtilitiesModule {
|
|||
abstract fun provideIntentProvider(
|
||||
intentProvider: RealIntentProvider
|
||||
): IntentProvider
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun provideChannelProvider(
|
||||
channelProvider: RealNotificationChannelProvider
|
||||
): NotificationChannelProvider
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun provideNotificationProvider(
|
||||
notificationProvider: RealNotificationProvider
|
||||
): NotificationProvider
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
*/
|
||||
package com.afollestad.nocknock.utilities.js
|
||||
|
||||
import android.util.Log
|
||||
import com.afollestad.nocknock.utilities.BuildConfig
|
||||
import org.mozilla.javascript.Context
|
||||
import org.mozilla.javascript.EvaluatorException
|
||||
import org.mozilla.javascript.Function
|
||||
|
@ -62,9 +60,6 @@ object JavaScript {
|
|||
}
|
||||
}
|
||||
|
||||
log(
|
||||
"Evaluated to $message ($success): $code"
|
||||
)
|
||||
return if (!success) message else null
|
||||
} finally {
|
||||
Context.exit()
|
||||
|
@ -73,10 +68,4 @@ object JavaScript {
|
|||
return e.message
|
||||
}
|
||||
}
|
||||
|
||||
private fun log(message: String) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d("JavaScript", message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Licensed under Apache-2.0
|
||||
*
|
||||
* Designed and developed by Aidan Follestad (@afollestad)
|
||||
*/
|
||||
package com.afollestad.nocknock.utilities.providers
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.NotificationChannel
|
||||
import android.os.Build.VERSION_CODES
|
||||
import javax.inject.Inject
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
interface NotificationChannelProvider {
|
||||
|
||||
/** @return null if the device doesn't have Android O. */
|
||||
fun create(
|
||||
id: String,
|
||||
title: String,
|
||||
description: String,
|
||||
importance: Int
|
||||
): NotificationChannel?
|
||||
}
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
class RealNotificationChannelProvider @Inject constructor(
|
||||
private val sdkProvider: SdkProvider
|
||||
) : NotificationChannelProvider {
|
||||
|
||||
@TargetApi(VERSION_CODES.O)
|
||||
override fun create(
|
||||
id: String,
|
||||
title: String,
|
||||
description: String,
|
||||
importance: Int
|
||||
): NotificationChannel? {
|
||||
if (!sdkProvider.hasOreo()) {
|
||||
return null
|
||||
}
|
||||
return NotificationChannel(id, title, importance)
|
||||
.apply {
|
||||
this.description = description
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Licensed under Apache-2.0
|
||||
*
|
||||
* Designed and developed by Aidan Follestad (@afollestad)
|
||||
*/
|
||||
package com.afollestad.nocknock.utilities.providers
|
||||
|
||||
import android.app.Application
|
||||
import android.app.Notification
|
||||
import android.app.PendingIntent
|
||||
import android.graphics.Bitmap
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationCompat.DEFAULT_VIBRATE
|
||||
import javax.inject.Inject
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
interface NotificationProvider {
|
||||
|
||||
fun create(
|
||||
channelId: String,
|
||||
title: String,
|
||||
content: String,
|
||||
intent: PendingIntent,
|
||||
smallIcon: Int,
|
||||
largeIcon: Bitmap
|
||||
): Notification
|
||||
}
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
class RealNotificationProvider @Inject constructor(
|
||||
private val app: Application
|
||||
) : NotificationProvider {
|
||||
|
||||
override fun create(
|
||||
channelId: String,
|
||||
title: String,
|
||||
content: String,
|
||||
intent: PendingIntent,
|
||||
smallIcon: Int,
|
||||
largeIcon: Bitmap
|
||||
): Notification {
|
||||
return NotificationCompat.Builder(app, channelId)
|
||||
.setContentTitle(title)
|
||||
.setContentText(content)
|
||||
.setContentIntent(intent)
|
||||
.setSmallIcon(smallIcon)
|
||||
.setLargeIcon(largeIcon)
|
||||
.setAutoCancel(true)
|
||||
.setDefaults(DEFAULT_VIBRATE)
|
||||
.build()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Licensed under Apache-2.0
|
||||
*
|
||||
* Designed and developed by Aidan Follestad (@afollestad)
|
||||
*/
|
||||
package com.afollestad.nocknock.utilities.providers
|
||||
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.os.Build.VERSION_CODES.O
|
||||
import javax.inject.Inject
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
interface SdkProvider {
|
||||
|
||||
fun hasOreo(): Boolean
|
||||
}
|
||||
|
||||
/** @author Aidan Follestad (@afollestad) */
|
||||
class RealSdkProvider @Inject constructor() : SdkProvider {
|
||||
|
||||
override fun hasOreo() = SDK_INT >= O
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
* Licensed under Apache-2.0
|
||||
*
|
||||
* Designed and developed by Aidan Follestad (@afollestad)
|
||||
*/
|
||||
package com.afollestad.nocknock.utilities.util
|
||||
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.os.Build.VERSION_CODES.O
|
||||
|
||||
fun hasOreo() = SDK_INT >= O
|
Loading…
Add table
Reference in a new issue