kopia lustrzana https://github.com/ryukoposting/Signal-Android
Add remote megaphone snooze capabilities.
rodzic
2ea5c7e3bc
commit
c357c35303
|
@ -538,6 +538,7 @@ dependencies {
|
|||
force = true
|
||||
}
|
||||
testImplementation testLibs.hamcrest.hamcrest
|
||||
testImplementation testLibs.mockk
|
||||
|
||||
testImplementation(testFixtures(project(":libsignal-service")))
|
||||
|
||||
|
|
|
@ -6,7 +6,10 @@ import android.database.Cursor
|
|||
import android.net.Uri
|
||||
import androidx.core.content.contentValuesOf
|
||||
import androidx.core.net.toUri
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import org.signal.core.util.delete
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.readToList
|
||||
import org.signal.core.util.requireInt
|
||||
import org.signal.core.util.requireLong
|
||||
|
@ -24,6 +27,8 @@ import java.util.concurrent.TimeUnit
|
|||
class RemoteMegaphoneDatabase(context: Context, databaseHelper: SignalDatabase) : Database(context, databaseHelper) {
|
||||
|
||||
companion object {
|
||||
private val TAG = Log.tag(RemoteMegaphoneDatabase::class.java)
|
||||
|
||||
private const val TABLE_NAME = "remote_megaphone"
|
||||
private const val ID = "_id"
|
||||
private const val UUID = "uuid"
|
||||
|
@ -44,6 +49,10 @@ class RemoteMegaphoneDatabase(context: Context, databaseHelper: SignalDatabase)
|
|||
private const val SECONDARY_ACTION_TEXT = "secondary_action_text"
|
||||
private const val SHOWN_AT = "shown_at"
|
||||
private const val FINISHED_AT = "finished_at"
|
||||
private const val PRIMARY_ACTION_DATA = "primary_action_data"
|
||||
private const val SECONDARY_ACTION_DATA = "secondary_action_data"
|
||||
private const val SNOOZED_AT = "snoozed_at"
|
||||
private const val SEEN_COUNT = "seen_count"
|
||||
|
||||
val CREATE_TABLE = """
|
||||
CREATE TABLE $TABLE_NAME (
|
||||
|
@ -65,7 +74,11 @@ class RemoteMegaphoneDatabase(context: Context, databaseHelper: SignalDatabase)
|
|||
$PRIMARY_ACTION_TEXT TEXT,
|
||||
$SECONDARY_ACTION_TEXT TEXT,
|
||||
$SHOWN_AT INTEGER DEFAULT 0,
|
||||
$FINISHED_AT INTEGER DEFAULT 0
|
||||
$FINISHED_AT INTEGER DEFAULT 0,
|
||||
$PRIMARY_ACTION_DATA TEXT DEFAULT NULL,
|
||||
$SECONDARY_ACTION_DATA TEXT DEFAULT NULL,
|
||||
$SNOOZED_AT INTEGER DEFAULT 0,
|
||||
$SEEN_COUNT INTEGER DEFAULT 0
|
||||
)
|
||||
""".trimIndent()
|
||||
|
||||
|
@ -99,7 +112,7 @@ class RemoteMegaphoneDatabase(context: Context, databaseHelper: SignalDatabase)
|
|||
.readToList { it.toRemoteMegaphoneRecord() }
|
||||
}
|
||||
|
||||
fun getPotentialMegaphonesAndClearOld(now: Long = System.currentTimeMillis()): List<RemoteMegaphoneRecord> {
|
||||
fun getPotentialMegaphonesAndClearOld(now: Long): List<RemoteMegaphoneRecord> {
|
||||
val records: List<RemoteMegaphoneRecord> = readableDatabase
|
||||
.select()
|
||||
.from(TABLE_NAME)
|
||||
|
@ -148,6 +161,17 @@ class RemoteMegaphoneDatabase(context: Context, databaseHelper: SignalDatabase)
|
|||
.run()
|
||||
}
|
||||
|
||||
fun snooze(remote: RemoteMegaphoneRecord) {
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(
|
||||
SEEN_COUNT to remote.seenCount + 1,
|
||||
SNOOZED_AT to System.currentTimeMillis()
|
||||
)
|
||||
.where("$UUID = ?", remote.uuid)
|
||||
.run()
|
||||
}
|
||||
|
||||
fun clearImageUrl(uuid: String) {
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
|
@ -192,7 +216,11 @@ class RemoteMegaphoneDatabase(context: Context, databaseHelper: SignalDatabase)
|
|||
BODY to body,
|
||||
PRIMARY_ACTION_TEXT to primaryActionText,
|
||||
SECONDARY_ACTION_TEXT to secondaryActionText,
|
||||
FINISHED_AT to finishedAt
|
||||
FINISHED_AT to finishedAt,
|
||||
PRIMARY_ACTION_DATA to primaryActionData?.toString(),
|
||||
SECONDARY_ACTION_DATA to secondaryActionData?.toString(),
|
||||
SNOOZED_AT to snoozedAt,
|
||||
SEEN_COUNT to seenCount
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -216,7 +244,24 @@ class RemoteMegaphoneDatabase(context: Context, databaseHelper: SignalDatabase)
|
|||
primaryActionText = requireString(PRIMARY_ACTION_TEXT),
|
||||
secondaryActionText = requireString(SECONDARY_ACTION_TEXT),
|
||||
shownAt = requireLong(SHOWN_AT),
|
||||
finishedAt = requireLong(FINISHED_AT)
|
||||
finishedAt = requireLong(FINISHED_AT),
|
||||
primaryActionData = requireString(PRIMARY_ACTION_DATA).parseJsonObject(),
|
||||
secondaryActionData = requireString(SECONDARY_ACTION_DATA).parseJsonObject(),
|
||||
snoozedAt = requireLong(SNOOZED_AT),
|
||||
seenCount = requireInt(SEEN_COUNT)
|
||||
)
|
||||
}
|
||||
|
||||
private fun String?.parseJsonObject(): JSONObject? {
|
||||
if (this == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return try {
|
||||
JSONObject(this)
|
||||
} catch (e: JSONException) {
|
||||
Log.w(TAG, "Unable to parse data", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V159_ThreadUnreadSe
|
|||
import org.thoughtcrime.securesms.database.helpers.migration.V160_SmsMmsExportedIndexMigration
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V161_StorySendMessageIdIndex
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V162_ThreadUnreadSelfMentionCountFixup
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V163_RemoteMegaphoneSnoozeSupportMigration
|
||||
|
||||
/**
|
||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||
|
@ -26,7 +27,7 @@ object SignalDatabaseMigrations {
|
|||
|
||||
val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
|
||||
|
||||
const val DATABASE_VERSION = 162
|
||||
const val DATABASE_VERSION = 163
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
|
@ -85,6 +86,10 @@ object SignalDatabaseMigrations {
|
|||
if (oldVersion < 162) {
|
||||
V162_ThreadUnreadSelfMentionCountFixup.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
|
||||
if (oldVersion < 163) {
|
||||
V163_RemoteMegaphoneSnoozeSupportMigration.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package org.thoughtcrime.securesms.database.helpers.migration
|
||||
|
||||
import android.app.Application
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabase
|
||||
|
||||
/**
|
||||
* Add columns needed to track remote megaphone specific snooze rates.
|
||||
*/
|
||||
object V163_RemoteMegaphoneSnoozeSupportMigration : SignalDatabaseMigration {
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
if (columnMissing(db, "primary_action_data")) {
|
||||
db.execSQL("ALTER TABLE remote_megaphone ADD COLUMN primary_action_data TEXT DEFAULT NULL")
|
||||
}
|
||||
|
||||
if (columnMissing(db, "secondary_action_data")) {
|
||||
db.execSQL("ALTER TABLE remote_megaphone ADD COLUMN secondary_action_data TEXT DEFAULT NULL")
|
||||
}
|
||||
|
||||
if (columnMissing(db, "snoozed_at")) {
|
||||
db.execSQL("ALTER TABLE remote_megaphone ADD COLUMN snoozed_at INTEGER DEFAULT 0")
|
||||
}
|
||||
|
||||
if (columnMissing(db, "seen_count")) {
|
||||
db.execSQL("ALTER TABLE remote_megaphone ADD COLUMN seen_count INTEGER DEFAULT 0")
|
||||
}
|
||||
}
|
||||
|
||||
private fun columnMissing(db: SupportSQLiteDatabase, column: String): Boolean {
|
||||
db.query("PRAGMA table_info(remote_megaphone)", null).use { cursor ->
|
||||
val nameColumnIndex = cursor.getColumnIndexOrThrow("name")
|
||||
while (cursor.moveToNext()) {
|
||||
val name = cursor.getString(nameColumnIndex)
|
||||
if (name == column) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package org.thoughtcrime.securesms.database.model
|
||||
|
||||
import android.net.Uri
|
||||
import org.json.JSONObject
|
||||
|
||||
/**
|
||||
* Represents a Remote Megaphone.
|
||||
|
@ -24,7 +25,11 @@ data class RemoteMegaphoneRecord(
|
|||
val primaryActionText: String?,
|
||||
val secondaryActionText: String?,
|
||||
val shownAt: Long = 0,
|
||||
val finishedAt: Long = 0
|
||||
val finishedAt: Long = 0,
|
||||
val primaryActionData: JSONObject? = null,
|
||||
val secondaryActionData: JSONObject? = null,
|
||||
val snoozedAt: Long = 0,
|
||||
val seenCount: Int = 0
|
||||
) {
|
||||
@get:JvmName("hasPrimaryAction")
|
||||
val hasPrimaryAction = primaryActionId != null && primaryActionText != null
|
||||
|
@ -32,6 +37,16 @@ data class RemoteMegaphoneRecord(
|
|||
@get:JvmName("hasSecondaryAction")
|
||||
val hasSecondaryAction = secondaryActionId != null && secondaryActionText != null
|
||||
|
||||
fun getDataForAction(actionId: ActionId): JSONObject? {
|
||||
return if (primaryActionId == actionId) {
|
||||
primaryActionData
|
||||
} else if (secondaryActionId == actionId) {
|
||||
secondaryActionData
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
enum class ActionId(val id: String, val isDonateAction: Boolean = false) {
|
||||
SNOOZE("snooze"),
|
||||
FINISH("finish"),
|
||||
|
|
|
@ -2,6 +2,9 @@ package org.thoughtcrime.securesms.jobs
|
|||
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode
|
||||
import org.json.JSONObject
|
||||
import org.signal.core.util.Hex
|
||||
import org.signal.core.util.ThreadUtil
|
||||
import org.signal.core.util.logging.Log
|
||||
|
@ -275,7 +278,9 @@ class RetrieveRemoteAnnouncementsJob private constructor(private val force: Bool
|
|||
title = megaphone.translation.title,
|
||||
body = megaphone.translation.body,
|
||||
primaryActionText = megaphone.translation.primaryCtaText,
|
||||
secondaryActionText = megaphone.translation.secondaryCtaText
|
||||
secondaryActionText = megaphone.translation.secondaryCtaText,
|
||||
primaryActionData = megaphone.remoteMegaphone.primaryCtaData?.takeIf { it is ObjectNode }?.let { JSONObject(it.toString()) },
|
||||
secondaryActionData = megaphone.remoteMegaphone.secondaryCtaData?.takeIf { it is ObjectNode }?.let { JSONObject(it.toString()) }
|
||||
)
|
||||
|
||||
SignalDatabase.remoteMegaphones.insert(record)
|
||||
|
@ -384,7 +389,9 @@ class RetrieveRemoteAnnouncementsJob private constructor(private val force: Bool
|
|||
@JsonProperty val showForNumberOfDays: Long?,
|
||||
@JsonProperty val conditionalId: String?,
|
||||
@JsonProperty val primaryCtaId: String?,
|
||||
@JsonProperty val secondaryCtaId: String?
|
||||
@JsonProperty val secondaryCtaId: String?,
|
||||
@JsonProperty val primaryCtaData: JsonNode?,
|
||||
@JsonProperty val secondaryCtaData: JsonNode?
|
||||
)
|
||||
|
||||
data class TranslatedReleaseNote(
|
||||
|
|
|
@ -307,7 +307,7 @@ public final class Megaphones {
|
|||
}
|
||||
|
||||
private static @NonNull Megaphone buildRemoteMegaphone(@NonNull Context context) {
|
||||
RemoteMegaphoneRecord record = RemoteMegaphoneRepository.getRemoteMegaphoneToShow();
|
||||
RemoteMegaphoneRecord record = RemoteMegaphoneRepository.getRemoteMegaphoneToShow(System.currentTimeMillis());
|
||||
|
||||
if (record != null) {
|
||||
Megaphone.Builder builder = new Megaphone.Builder(Event.REMOTE_MEGAPHONE, Megaphone.Style.BASIC)
|
||||
|
|
|
@ -4,7 +4,10 @@ import android.app.Application
|
|||
import android.content.Context
|
||||
import androidx.annotation.AnyThread
|
||||
import androidx.annotation.WorkerThread
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.badges.models.Badge
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
|
||||
import org.thoughtcrime.securesms.database.RemoteMegaphoneDatabase
|
||||
|
@ -19,16 +22,23 @@ import org.thoughtcrime.securesms.util.LocaleFeatureFlags
|
|||
import org.thoughtcrime.securesms.util.PlayServicesUtil
|
||||
import org.thoughtcrime.securesms.util.VersionTracker
|
||||
import java.util.Objects
|
||||
import kotlin.math.min
|
||||
import kotlin.time.Duration.Companion.days
|
||||
|
||||
/**
|
||||
* Access point for interacting with Remote Megaphones.
|
||||
*/
|
||||
object RemoteMegaphoneRepository {
|
||||
|
||||
private val TAG = Log.tag(RemoteMegaphoneRepository::class.java)
|
||||
|
||||
private val db: RemoteMegaphoneDatabase = SignalDatabase.remoteMegaphones
|
||||
private val context: Application = ApplicationDependencies.getApplication()
|
||||
|
||||
private val snooze: Action = Action { _, controller, _ -> controller.onMegaphoneSnooze(Megaphones.Event.REMOTE_MEGAPHONE) }
|
||||
private val snooze: Action = Action { _, controller, remote ->
|
||||
controller.onMegaphoneSnooze(Megaphones.Event.REMOTE_MEGAPHONE)
|
||||
db.snooze(remote)
|
||||
}
|
||||
|
||||
private val finish: Action = Action { context, controller, remote ->
|
||||
if (remote.imageUri != null) {
|
||||
|
@ -40,7 +50,7 @@ object RemoteMegaphoneRepository {
|
|||
|
||||
private val donate: Action = Action { context, controller, remote ->
|
||||
controller.onMegaphoneNavigationRequested(AppSettingsActivity.manageSubscriptions(context))
|
||||
finish.run(context, controller, remote)
|
||||
snooze.run(context, controller, remote)
|
||||
}
|
||||
|
||||
private val actions = mapOf(
|
||||
|
@ -65,12 +75,13 @@ object RemoteMegaphoneRepository {
|
|||
|
||||
@WorkerThread
|
||||
@JvmStatic
|
||||
fun getRemoteMegaphoneToShow(): RemoteMegaphoneRecord? {
|
||||
return db.getPotentialMegaphonesAndClearOld()
|
||||
fun getRemoteMegaphoneToShow(now: Long = System.currentTimeMillis()): RemoteMegaphoneRecord? {
|
||||
return db.getPotentialMegaphonesAndClearOld(now)
|
||||
.asSequence()
|
||||
.filter { it.imageUrl == null || it.imageUri != null }
|
||||
.filter { it.countries == null || LocaleFeatureFlags.shouldShowReleaseNote(it.uuid, it.countries) }
|
||||
.filter { it.conditionalId == null || checkCondition(it.conditionalId) }
|
||||
.filter { it.snoozedAt == 0L || checkSnooze(it, now) }
|
||||
.firstOrNull()
|
||||
}
|
||||
|
||||
|
@ -95,6 +106,17 @@ object RemoteMegaphoneRepository {
|
|||
}
|
||||
}
|
||||
|
||||
private fun checkSnooze(record: RemoteMegaphoneRecord, now: Long): Boolean {
|
||||
if (record.seenCount == 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
val gaps: JSONArray? = record.getDataForAction(ActionId.SNOOZE)?.getJSONArray("snoozeDurationDays")?.takeIf { it.length() > 0 }
|
||||
val gapDays: Int? = gaps?.getIntOrNull(record.seenCount - 1)
|
||||
|
||||
return gapDays == null || (record.snoozedAt + gapDays.days.inWholeMilliseconds <= now)
|
||||
}
|
||||
|
||||
private fun shouldShowDonateMegaphone(): Boolean {
|
||||
return VersionTracker.getDaysSinceFirstInstalled(context) >= 7 &&
|
||||
PlayServicesUtil.getPlayServicesStatus(context) == PlayServicesUtil.PlayServicesStatus.SUCCESS &&
|
||||
|
@ -108,4 +130,16 @@ object RemoteMegaphoneRepository {
|
|||
fun interface Action {
|
||||
fun run(context: Context, controller: MegaphoneActionController, remoteMegaphone: RemoteMegaphoneRecord)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the int at the specified index, or last index of array if larger then array length, or null if unable to parse json
|
||||
*/
|
||||
private fun JSONArray.getIntOrNull(index: Int): Int? {
|
||||
return try {
|
||||
getInt(min(index, length() - 1))
|
||||
} catch (e: JSONException) {
|
||||
Log.w(TAG, "Unable to parse", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
package org.thoughtcrime.securesms.megaphone
|
||||
|
||||
import android.app.Application
|
||||
import android.net.Uri
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkObject
|
||||
import io.mockk.unmockkObject
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers.notNullValue
|
||||
import org.hamcrest.Matchers.nullValue
|
||||
import org.json.JSONObject
|
||||
import org.junit.After
|
||||
import org.junit.AfterClass
|
||||
import org.junit.Before
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.thoughtcrime.securesms.SignalStoreRule
|
||||
import org.thoughtcrime.securesms.database.RemoteMegaphoneDatabase
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.model.RemoteMegaphoneRecord
|
||||
import org.thoughtcrime.securesms.util.toMillis
|
||||
import java.time.LocalDateTime
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* [RemoteMegaphoneRepository] is an Kotlin Object, which means it's like a singleton and thus maintains
|
||||
* state and dependencies across tests. You must be aware of this when mocking/testing.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE, application = Application::class)
|
||||
class RemoteMegaphoneRepositoryTest {
|
||||
|
||||
@get:Rule
|
||||
val signalStore: SignalStoreRule = SignalStoreRule()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
clearMocks(remoteMegaphoneDatabase)
|
||||
}
|
||||
|
||||
/** Should return null if no megaphones in database. */
|
||||
@Test
|
||||
fun getRemoteMegaphoneToShow_noMegaphones() {
|
||||
// GIVEN
|
||||
every { remoteMegaphoneDatabase.getPotentialMegaphonesAndClearOld(any()) } returns emptyList()
|
||||
|
||||
// WHEN
|
||||
val record = RemoteMegaphoneRepository.getRemoteMegaphoneToShow(0)
|
||||
|
||||
// THEN
|
||||
assertThat(record, nullValue())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRemoteMegaphoneToShow_oneMegaphone() {
|
||||
// GIVEN
|
||||
every { remoteMegaphoneDatabase.getPotentialMegaphonesAndClearOld(any()) } returns listOf(megaphone(1))
|
||||
|
||||
// WHEN
|
||||
val record = RemoteMegaphoneRepository.getRemoteMegaphoneToShow(0)
|
||||
|
||||
// THEN
|
||||
assertThat(record, notNullValue())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRemoteMegaphoneToShow_snoozedMegaphone() {
|
||||
// GIVEN
|
||||
val snoozed = megaphone(
|
||||
id = 1,
|
||||
seenCount = 1,
|
||||
snoozedAt = now.minusDays(1).toMillis(),
|
||||
secondaryActionId = RemoteMegaphoneRecord.ActionId.SNOOZE,
|
||||
secondaryActionData = JSONObject("{\"snoozeDurationDays\":[3]}")
|
||||
)
|
||||
|
||||
every { remoteMegaphoneDatabase.getPotentialMegaphonesAndClearOld(now.toMillis()) } returns listOf(snoozed)
|
||||
|
||||
// WHEN
|
||||
val record = RemoteMegaphoneRepository.getRemoteMegaphoneToShow(now.toMillis())
|
||||
|
||||
// THEN
|
||||
assertThat(record, nullValue())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRemoteMegaphoneToShow_oldSnoozedMegaphone() {
|
||||
// GIVEN
|
||||
val snoozed = megaphone(
|
||||
id = 1,
|
||||
seenCount = 1,
|
||||
snoozedAt = now.minusDays(5).toMillis(),
|
||||
secondaryActionId = RemoteMegaphoneRecord.ActionId.SNOOZE,
|
||||
secondaryActionData = JSONObject("{\"snoozeDurationDays\":[3]}")
|
||||
)
|
||||
|
||||
every { remoteMegaphoneDatabase.getPotentialMegaphonesAndClearOld(now.toMillis()) } returns listOf(snoozed)
|
||||
|
||||
// WHEN
|
||||
val record = RemoteMegaphoneRepository.getRemoteMegaphoneToShow(now.toMillis())
|
||||
|
||||
// THEN
|
||||
assertThat(record, notNullValue())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRemoteMegaphoneToShow_multipleOldSnoozedMegaphone() {
|
||||
// GIVEN
|
||||
val snoozed = megaphone(
|
||||
id = 1,
|
||||
seenCount = 5,
|
||||
snoozedAt = now.minusDays(8).toMillis(),
|
||||
secondaryActionId = RemoteMegaphoneRecord.ActionId.SNOOZE,
|
||||
secondaryActionData = JSONObject("{\"snoozeDurationDays\":[3, 5, 7]}")
|
||||
)
|
||||
|
||||
every { remoteMegaphoneDatabase.getPotentialMegaphonesAndClearOld(now.toMillis()) } returns listOf(snoozed)
|
||||
|
||||
// WHEN
|
||||
val record = RemoteMegaphoneRepository.getRemoteMegaphoneToShow(now.toMillis())
|
||||
|
||||
// THEN
|
||||
assertThat(record, notNullValue())
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val now = LocalDateTime.of(2021, 11, 5, 12, 0)
|
||||
|
||||
private val remoteMegaphoneDatabase: RemoteMegaphoneDatabase = mockk()
|
||||
|
||||
@BeforeClass
|
||||
@JvmStatic
|
||||
fun classSetup() {
|
||||
mockkObject(SignalDatabase.Companion)
|
||||
every { SignalDatabase.remoteMegaphones } returns remoteMegaphoneDatabase
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@JvmStatic
|
||||
fun classCleanup() {
|
||||
unmockkObject(SignalDatabase.Companion)
|
||||
}
|
||||
|
||||
fun megaphone(
|
||||
id: Long,
|
||||
priority: Long = 100,
|
||||
uuid: String = UUID.randomUUID().toString(),
|
||||
countries: String? = null,
|
||||
minimumVersion: Int = 100,
|
||||
doNotShowBefore: Long = 0,
|
||||
doNotShowAfter: Long = Long.MAX_VALUE,
|
||||
showForNumberOfDays: Long = Long.MAX_VALUE,
|
||||
conditionalId: String? = null,
|
||||
primaryActionId: RemoteMegaphoneRecord.ActionId? = null,
|
||||
secondaryActionId: RemoteMegaphoneRecord.ActionId? = null,
|
||||
imageUrl: String? = null,
|
||||
imageUri: Uri? = null,
|
||||
title: String = "",
|
||||
body: String = "",
|
||||
primaryActionText: String? = null,
|
||||
secondaryActionText: String? = null,
|
||||
shownAt: Long = 0,
|
||||
finishedAt: Long = 0,
|
||||
primaryActionData: JSONObject? = null,
|
||||
secondaryActionData: JSONObject? = null,
|
||||
snoozedAt: Long = 0,
|
||||
seenCount: Int = 0
|
||||
): RemoteMegaphoneRecord {
|
||||
return RemoteMegaphoneRecord(
|
||||
id,
|
||||
priority,
|
||||
uuid,
|
||||
countries,
|
||||
minimumVersion,
|
||||
doNotShowBefore,
|
||||
doNotShowAfter,
|
||||
showForNumberOfDays,
|
||||
conditionalId,
|
||||
primaryActionId,
|
||||
secondaryActionId,
|
||||
imageUrl,
|
||||
imageUri,
|
||||
title,
|
||||
body,
|
||||
primaryActionText,
|
||||
secondaryActionText,
|
||||
shownAt,
|
||||
finishedAt,
|
||||
primaryActionData,
|
||||
secondaryActionData,
|
||||
snoozedAt,
|
||||
seenCount,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -155,6 +155,7 @@ dependencyResolutionManagement {
|
|||
alias('hamcrest-hamcrest').to('org.hamcrest:hamcrest:2.2')
|
||||
alias('assertj-core').to('org.assertj:assertj-core:3.11.1')
|
||||
alias('square-okhttp-mockserver').to('com.squareup.okhttp3:mockwebserver:3.12.13')
|
||||
alias('mockk').to('io.mockk:mockk:1.13.2')
|
||||
|
||||
alias('conscrypt-openjdk-uber').to('org.conscrypt:conscrypt-openjdk-uber:2.0.0')
|
||||
}
|
||||
|
|
|
@ -2569,6 +2569,86 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="a6a8701ed35259ead9c7fc86e855e26559050e0a60a3be66a8f5c327c53eeaf8" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.mockk" name="mockk" version="1.13.2">
|
||||
<artifact name="mockk-1.13.2.module">
|
||||
<sha256 value="763ca22e765cc710ef5ba32c8e016a31c0217579f6e61b173282e9338d2dd190" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="mockk-metadata-1.13.2.jar">
|
||||
<sha256 value="5a01958c55e968afb2d03c73f0225f3285ee75a51aa0013071972795b83ba02c" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.mockk" name="mockk-agent" version="1.13.2">
|
||||
<artifact name="mockk-agent-1.13.2.module">
|
||||
<sha256 value="4ada00e221245eda8ac728e24d8fedffd4ffc7ebeb7dd600057f544000e020ab" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="mockk-agent-metadata-1.13.2.jar">
|
||||
<sha256 value="ec1468af9a0cb896126c1d0093246854a347192eda2e88ed45782bb56ca72982" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.mockk" name="mockk-agent-api" version="1.13.2">
|
||||
<artifact name="mockk-agent-api-1.13.2.module">
|
||||
<sha256 value="eb8a5b62cd9e2030da816dbad8b00cba108757eca11871629c7a2af47232ea12" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="mockk-agent-api-metadata-1.13.2.jar">
|
||||
<sha256 value="a2e490f6424c49ce98ca42ca191731ea6ccae3914adbc846761e10474f7bbae1" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.mockk" name="mockk-agent-api-jvm" version="1.13.2">
|
||||
<artifact name="mockk-agent-api-jvm-1.13.2.jar">
|
||||
<sha256 value="62baf321fd6a5121851b56800c20e07d5d4162f3f5866a8cd0d62cdd204588d4" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="mockk-agent-api-jvm-1.13.2.module">
|
||||
<sha256 value="801ad0eabd00490bc47543ded2804c059324360280b75e375d2b91b44b2c7c0e" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.mockk" name="mockk-agent-jvm" version="1.13.2">
|
||||
<artifact name="mockk-agent-jvm-1.13.2.jar">
|
||||
<sha256 value="ce89631cd9a1cffd7032342b0b48724cd84640083e9e13a39b3e3a019c866774" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="mockk-agent-jvm-1.13.2.module">
|
||||
<sha256 value="f3378af6f8a84f064f55420b7c9c7be8eda238233dcf9be6515277f1fb5c4d5f" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.mockk" name="mockk-core" version="1.13.2">
|
||||
<artifact name="mockk-core-1.13.2.module">
|
||||
<sha256 value="87b25b5325eeb89c7807846c4b99a8c583bf6b43399c27ba1df513d59e0ce915" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="mockk-core-metadata-1.13.2.jar">
|
||||
<sha256 value="a2e490f6424c49ce98ca42ca191731ea6ccae3914adbc846761e10474f7bbae1" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.mockk" name="mockk-core-jvm" version="1.13.2">
|
||||
<artifact name="mockk-core-jvm-1.13.2.jar">
|
||||
<sha256 value="485cb35c61fe764a58c6a015060f977758392654de4afcda36353aeb7a9c634f" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="mockk-core-jvm-1.13.2.module">
|
||||
<sha256 value="632a2aeacbd83e6b4603a241eb5d06b2d7f90c230fa30d35abb1e8a2e512813f" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.mockk" name="mockk-dsl" version="1.13.2">
|
||||
<artifact name="mockk-dsl-1.13.2.module">
|
||||
<sha256 value="a902b145ef6fc1280e4b74d6f89d44ec129fee722e715a48db8eb9fb39633c96" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="mockk-dsl-metadata-1.13.2.jar">
|
||||
<sha256 value="794a42eb917780f99fe65bdc0d5483ab9a19bd3c532feb8c01c9586f5873f890" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.mockk" name="mockk-dsl-jvm" version="1.13.2">
|
||||
<artifact name="mockk-dsl-jvm-1.13.2.jar">
|
||||
<sha256 value="994203a45ea608078cbe746d8aa4855f4274cf2913fb1e31c27f3d2a096c428a" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="mockk-dsl-jvm-1.13.2.module">
|
||||
<sha256 value="5e631c733c03a9ddc7300fc7000e9537a9039ea1d25c9e1244088fcdd253cc13" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.mockk" name="mockk-jvm" version="1.13.2">
|
||||
<artifact name="mockk-jvm-1.13.2.jar">
|
||||
<sha256 value="2917b9beb291078425a108a34b3611398ca9e8c58dcdf5a024c463971671b20b" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="mockk-jvm-1.13.2.module">
|
||||
<sha256 value="c15b38f37ee61192e3f8640619c40b61b8cb39e931dd87e2873cbc3ca84c72d7" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="io.netty" name="netty-buffer" version="4.1.34.Final">
|
||||
<artifact name="netty-buffer-4.1.34.Final.jar">
|
||||
<sha256 value="39dfe88df8505fd01fbf9c1dbb6b6fa9b0297e453c3dc4ce039ea578aea2eaa3" origin="Generated by Gradle"/>
|
||||
|
@ -3304,6 +3384,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="1e1f57209f7238c3fd1735a1b9339a56565507dca249f8371bf59d91f601aeaa" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlin" name="kotlin-reflect" version="1.7.10">
|
||||
<artifact name="kotlin-reflect-1.7.10.jar">
|
||||
<sha256 value="187c5e5a588a6ed18c3a41b54df138a5944121bdb396be1c3fa4abee67397955" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlin" name="kotlin-script-runtime" version="1.5.31">
|
||||
<artifact name="kotlin-script-runtime-1.5.31.jar">
|
||||
<sha256 value="24e450fee7645ed3590981dddccf397c0d9ebb725815c94c4f555cc3db2f9f96" origin="Generated by Gradle"/>
|
||||
|
@ -3449,6 +3534,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="f1b0634dbb94172038463020bb2dd45ca26849f8ce29d625acb0f1569d11dbee" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-jdk7" version="1.7.10">
|
||||
<artifact name="kotlin-stdlib-jdk7-1.7.10.jar">
|
||||
<sha256 value="54f61351b1936ad88f4e53059fe781e723eae51d78ed9e7422d8b403574ec682" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-jdk8" version="1.3.71">
|
||||
<artifact name="kotlin-stdlib-jdk8-1.3.71.jar">
|
||||
<sha256 value="a22192ac779ba8eff09d07084ae503e8be9e7c8ca1cb2b511ff8af4c68d83d66" origin="Generated by Gradle"/>
|
||||
|
@ -3479,6 +3569,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="dab45489b47736d59fce44b80676f1947a9b6bcab10fd60e878a83bd82a6954c" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-jdk8" version="1.7.10">
|
||||
<artifact name="kotlin-stdlib-jdk8-1.7.10.jar">
|
||||
<sha256 value="8aafdd60c94f454c92e5066d266a5ed53ecc63c78f623b3fd9db56fea4032873" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlin" name="kotlin-test" version="1.3.71">
|
||||
<artifact name="kotlin-test-1.3.71.jar">
|
||||
<sha256 value="d9236ecd3c5b22c23e2892537276f3c1fab63f439b5bdceb115a8768aacb3998" origin="Generated by Gradle"/>
|
||||
|
@ -3546,6 +3641,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="558a3e6e5cc501f13aac0436bd08bb342d10de9f8bcfd3ba6d582f433e92c3b1" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-android" version="1.6.4">
|
||||
<artifact name="kotlinx-coroutines-android-1.6.4.jar">
|
||||
<sha256 value="3fdc0eed5bc4b83ee9622774520a2db25470370eacd1581cac1e37704f095b00" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="kotlinx-coroutines-android-1.6.4.module">
|
||||
<sha256 value="68516559e6f84a621b9783cd892a64630ccd7875843588ddb3f0501425e33f15" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core" version="1.4.1">
|
||||
<artifact name="kotlinx-coroutines-core-1.4.1.module">
|
||||
<sha256 value="3c00e44941f134b18cadbc5f18ab7b7f23d3ef1f78af95e344cb9c605db21a44" origin="Generated by Gradle"/>
|
||||
|
@ -3564,6 +3667,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="67c807c236e19c32020fc5ba82b273fda1e76cad50693f0917efe6071f159db9" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core" version="1.6.4">
|
||||
<artifact name="kotlinx-coroutines-core-1.6.4.module">
|
||||
<sha256 value="a6eed4a1835588e7c84fcd7b0475fce9a7b3444c870ebc797b88ba64ccf4576b" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core-jvm" version="1.4.1">
|
||||
<artifact name="kotlinx-coroutines-core-jvm-1.4.1.jar">
|
||||
<sha256 value="6d2f87764b6638f27aff12ed380db4b63c9d46ba55dc32683a650598fa5a3e22" origin="Generated by Gradle"/>
|
||||
|
@ -3596,6 +3704,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="f31b672a11feb0ee49d5d49143067e93c33f5866768ae42b9a324b53cdad36e1" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core-jvm" version="1.6.4">
|
||||
<artifact name="kotlinx-coroutines-core-jvm-1.6.4.jar">
|
||||
<sha256 value="c24c8bb27bb320c4a93871501a7e5e0c61607638907b197aef675513d4c820be" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="kotlinx-coroutines-core-jvm-1.6.4.module">
|
||||
<sha256 value="0d94c8a41483e7c2707ebd693e1b1357a84152998ce85550ebbc54ca4321a3a7" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core-metadata" version="1.4.1">
|
||||
<artifact name="kotlinx-coroutines-core-metadata-1.4.1-all.jar">
|
||||
<sha256 value="877057d99a7fff9282059ba6631a9039bf3b54795d397b7e69a67363b7d2dcfe" origin="Generated by Gradle"/>
|
||||
|
@ -3663,6 +3779,19 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="25de454b3add67654d6691b53de7593b502967b5ff549547b104d7961f1a52bd" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit" name="junit-bom" version="5.8.2">
|
||||
<artifact name="junit-bom-5.8.2.module">
|
||||
<sha256 value="40cfad993fa70ecdf2af74d0c56da1484ee220964be8f932cfe632be9a2733fa" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.jupiter" name="junit-jupiter" version="5.8.2">
|
||||
<artifact name="junit-jupiter-5.8.2.jar">
|
||||
<sha256 value="4f5c1cc6432244cd16e36aa0e02b74bce34a81ff95a13d63d50951ec4ce3f4bd" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="junit-jupiter-5.8.2.module">
|
||||
<sha256 value="d9df47b3c7431883ab1f1f1d820c2980ebcbd753edc4c82b99bf5ec2c533ad2e" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.jupiter" name="junit-jupiter-api" version="5.7.0">
|
||||
<artifact name="junit-jupiter-api-5.7.0.jar">
|
||||
<sha256 value="b03f78e0daeed2d77a0af9bcd662b4cdb9693f7ee72e01a539b508b84c63d182" origin="Generated by Gradle"/>
|
||||
|
@ -3671,6 +3800,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="d1a7bae6cd44ad6d96715261410eef2338a494436d667280d1373a47c17e241c" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.jupiter" name="junit-jupiter-api" version="5.8.2">
|
||||
<artifact name="junit-jupiter-api-5.8.2.jar">
|
||||
<sha256 value="1808ee87e0f718cd6e25f3b75afc17956ac8a3edc48c7e9bab9f19f9a79e3801" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="junit-jupiter-api-5.8.2.module">
|
||||
<sha256 value="7e9af4dfff6267acddd157d9e11ba0d5dc91b332fa74bc4c65939e4517a1b770" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.jupiter" name="junit-jupiter-engine" version="5.7.0">
|
||||
<artifact name="junit-jupiter-engine-5.7.0.jar">
|
||||
<sha256 value="dfa26af94644ac2612dde6625852fcb550a0d21caa243257de54cba738ba87af" origin="Generated by Gradle"/>
|
||||
|
@ -3679,6 +3816,22 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="c36bda48228eef5c40cdc9a9d6303bb848382cdb0884b3677d49182b4ec7a1a4" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.jupiter" name="junit-jupiter-engine" version="5.8.2">
|
||||
<artifact name="junit-jupiter-engine-5.8.2.jar">
|
||||
<sha256 value="753b7726cdd158bb34cedb94c161e2291896f47832a1e9eda53d970020a8184e" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="junit-jupiter-engine-5.8.2.module">
|
||||
<sha256 value="a56204c716c2379970ca8e3fe2a72e3a030cd9027328d3ce1457dd10c0150e7e" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.jupiter" name="junit-jupiter-params" version="5.8.2">
|
||||
<artifact name="junit-jupiter-params-5.8.2.jar">
|
||||
<sha256 value="d1c22d6fe5483568c08c8913f34abd2303490c3480ce6c18a2ea31c65e44102a" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="junit-jupiter-params-5.8.2.module">
|
||||
<sha256 value="5023e4e3ec156ec6bd3cf655f3070cfc5a3e8aad5d51b4bbe025a792e9498d73" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.platform" name="junit-platform-commons" version="1.7.0">
|
||||
<artifact name="junit-platform-commons-1.7.0.jar">
|
||||
<sha256 value="5330ee87cc7586e6e25175a34e9251624ff12ff525269d3415d0b4ca519b6fea" origin="Generated by Gradle"/>
|
||||
|
@ -3687,6 +3840,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="b0a5c7a1b7e409d1f5cc963d9aea1c77c34b90e163d6842a4489c6aa07ff8ee2" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.platform" name="junit-platform-commons" version="1.8.2">
|
||||
<artifact name="junit-platform-commons-1.8.2.jar">
|
||||
<sha256 value="d2e015fca7130e79af2f4608dc54415e4b10b592d77333decb4b1a274c185050" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="junit-platform-commons-1.8.2.module">
|
||||
<sha256 value="342847d3046fea435595692db4f05d5f039e0e1d1e204f4d5755902557082626" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.platform" name="junit-platform-engine" version="1.7.0">
|
||||
<artifact name="junit-platform-engine-1.7.0.jar">
|
||||
<sha256 value="75f21a20dc594afdc875736725b408cec6d0344874d29f34b2dd3075500236f2" origin="Generated by Gradle"/>
|
||||
|
@ -3695,6 +3856,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="6510a9fa881cef42d41485538dbc54749426db1e0b14ec433915ea5f2448079a" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.platform" name="junit-platform-engine" version="1.8.2">
|
||||
<artifact name="junit-platform-engine-1.8.2.jar">
|
||||
<sha256 value="0b7d000f8c3e8e5f7d6b819649936e7b9938314e87c8f983805218ea57567e59" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="junit-platform-engine-1.8.2.module">
|
||||
<sha256 value="eba77b36efdf75a67f46438333825f9e448f550d521e7249d950358580ee636b" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.junit.platform" name="junit-platform-launcher" version="1.7.0">
|
||||
<artifact name="junit-platform-launcher-1.7.0.jar">
|
||||
<sha256 value="fbdc748fde4c4279fe1d3c607447cb3b7ccd45d7338fc574f8a894ddf2d16818" origin="Generated by Gradle"/>
|
||||
|
@ -4026,6 +4195,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
|||
<sha256 value="cdba07964d1bb40a0761485c6b1e8c2f8fd9eb1d19c53928ac0d7f9510105c57" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.slf4j" name="slf4j-api" version="1.7.36">
|
||||
<artifact name="slf4j-api-1.7.36.jar">
|
||||
<sha256 value="d3ef575e3e4979678dc01bf1dcce51021493b4d11fb7f1be8ad982877c16a1c0" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.smali" name="dexlib2" version="2.2.4">
|
||||
<artifact name="dexlib2-2.2.4.jar">
|
||||
<sha256 value="cb2677bfb66cfbc954e96e806ac6bda13051ad37754f9d1bcce38514e50e41e6" origin="Generated by Gradle"/>
|
||||
|
|
Ładowanie…
Reference in New Issue