Commit d67c32db authored by Daniel Wolf's avatar Daniel Wolf
Browse files

Merge branch 'master' of https://git.frostnerd.com/PublicAndroidApps/smokescreen into translations

parents 3e79aa20 b62c6ae1
image: openjdk:8-jdk
variables:
ANDROID_COMPILE_SDK: "28"
ANDROID_BUILD_TOOLS: "28.0.2"
ANDROID_SDK_TOOLS: "26.1.1"
stages:
......@@ -9,7 +8,7 @@ stages:
- build
before_script:
- source /home/public/android-sdk-linux/initAndroid.sh -s ${ANDROID_COMPILE_SDK} -b ${ANDROID_BUILD_TOOLS}
- source /home/public/android-sdk-linux/initAndroid.sh -s ${ANDROID_COMPILE_SDK}
build_debug:
......
......@@ -54,6 +54,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
leakCanary {
initWith buildTypes.debug
}
fdroid {
initWith release
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
......@@ -89,16 +92,16 @@ android {
}
dependencies {
def room_version = "2.1.0"
def room_version = "2.2.0-alpha01"
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0-M2'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0-M2'
implementation 'com.frostnerd.utilskt:preferences:1.5.12' // https://git.frostnerd.com/AndroidUtils/preferenceskt (Accessible after logging in [free of charge])
implementation 'com.frostnerd.utilskt:navigationdraweractivity:1.3.18' // https://git.frostnerd.com/AndroidUtils/navigationdraweractivity (Accessible after logging in [free of charge])
implementation 'com.frostnerd.utilskt:encrypteddnstunnelproxy:1.5.119' // https://git.frostnerd.com/AndroidUtils/encrypteddnstunnelproxy
implementation 'com.frostnerd.utilskt:preferences:1.5.14' // https://git.frostnerd.com/AndroidUtils/preferenceskt (Accessible after logging in [free of charge])
implementation 'com.frostnerd.utilskt:navigationdraweractivity:1.3.19' // https://git.frostnerd.com/AndroidUtils/navigationdraweractivity (Accessible after logging in [free of charge])
implementation 'com.frostnerd.utilskt:encrypteddnstunnelproxy:1.5.123' // https://git.frostnerd.com/AndroidUtils/encrypteddnstunnelproxy
implementation 'com.frostnerd.utilskt:general:1.0.16' // https://git.frostnerd.com/AndroidUtils/generalkt (Accessible after logging in [free of charge])
implementation 'com.frostnerd.utilskt:adapters:1.1.1' // https://git.frostnerd.com/AndroidUtils/Adapters (Accessible after logging in [free of charge])
......@@ -115,9 +118,9 @@ dependencies {
implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0'
implementation 'com.github.jorgecastilloprz:fabprogresscircle:1.01@aar'
implementation 'com.squareup.leakcanary:leaksentry:2.0-alpha-3'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-alpha-3'
leakCanaryImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-alpha-3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
......
{
"formatVersion": 1,
"database": {
"version": 8,
"identityHash": "eefd1e309b2389e1e629ab2f0cbd21fa",
"entities": [
{
"tableName": "CachedResponse",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`dnsName` TEXT NOT NULL, `type` INTEGER NOT NULL, `records` TEXT NOT NULL, PRIMARY KEY(`dnsName`, `type`))",
"fields": [
{
"fieldPath": "dnsName",
"columnName": "dnsName",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "records",
"columnName": "records",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"dnsName",
"type"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DnsQuery",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` INTEGER NOT NULL, `name` TEXT NOT NULL, `askedServer` TEXT, `fromCache` INTEGER NOT NULL, `questionTime` INTEGER NOT NULL, `responseTime` INTEGER NOT NULL, `responses` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "askedServer",
"columnName": "askedServer",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "fromCache",
"columnName": "fromCache",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "questionTime",
"columnName": "questionTime",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "responseTime",
"columnName": "responseTime",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "responses",
"columnName": "responses",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DnsRule",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `stagingType` INTEGER NOT NULL, `type` INTEGER NOT NULL, `host` TEXT NOT NULL, `target` TEXT NOT NULL, `ipv6Target` TEXT, `importedFrom` INTEGER, FOREIGN KEY(`importedFrom`) REFERENCES `HostSource`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "stagingType",
"columnName": "stagingType",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "host",
"columnName": "host",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "target",
"columnName": "target",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "ipv6Target",
"columnName": "ipv6Target",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "importedFrom",
"columnName": "importedFrom",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_DnsRule_importedFrom",
"unique": false,
"columnNames": [
"importedFrom"
],
"createSql": "CREATE INDEX IF NOT EXISTS `index_DnsRule_importedFrom` ON `${TABLE_NAME}` (`importedFrom`)"
},
{
"name": "index_DnsRule_host_type_stagingType",
"unique": true,
"columnNames": [
"host",
"type",
"stagingType"
],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_DnsRule_host_type_stagingType` ON `${TABLE_NAME}` (`host`, `type`, `stagingType`)"
}
],
"foreignKeys": [
{
"table": "HostSource",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"importedFrom"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "HostSource",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `enabled` INTEGER NOT NULL, `name` TEXT NOT NULL, `source` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "enabled",
"columnName": "enabled",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "source",
"columnName": "source",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'eefd1e309b2389e1e629ab2f0cbd21fa')"
]
}
}
\ No newline at end of file
......@@ -96,4 +96,14 @@
<item>1.0 Beta-Adblock (Build 40)</item>
<item>@string/changelog_build_39_1</item>
</string-array>
<string-array name="changelog_build_41">
<item>1.0 Beta (Build 41)</item>
<item>@string/changelog_build_40_1</item>
<item>@string/changelog_build_40_2</item>
<item>@string/changelog_build_40_3</item>
<item>@string/changelog_build_40_4</item>
<item>@string/changelog_build_40_5</item>
<item>@string/changelog_build_40_6</item>
</string-array>
</resources>
\ No newline at end of file
......@@ -31,9 +31,11 @@ import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_dns_rules.*
import kotlinx.android.synthetic.main.item_datasource.view.*
import kotlinx.android.synthetic.main.item_datasource.view.cardContent
import kotlinx.android.synthetic.main.item_datasource.view.delete
import kotlinx.android.synthetic.main.item_datasource.view.enable
import kotlinx.android.synthetic.main.item_datasource.view.text
import kotlinx.android.synthetic.main.item_datasource_rules.view.*
import kotlinx.android.synthetic.main.item_dnsrule_host.view.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
......@@ -201,7 +203,14 @@ class DnsRuleActivity : BaseActivity() {
else -> it
}
}
val id = getDatabase().dnsRuleDao().insertIgnore(newRule)
val id = if(newRule.isWhitelistRule()) {
getDatabase().dnsRuleDao().insertWhitelist(newRule)
if(userDnsRules.any {
println("$it vs $newRule")
it.host == newRule.host && it.type == newRule.type
}) -1L
else 0L
} else getDatabase().dnsRuleDao().insertIgnore(newRule)
if(id != -1L) {
userDnsRules.add(insertPos, newRule)
val wereRulesShown = showUserRules
......@@ -229,10 +238,14 @@ class DnsRuleActivity : BaseActivity() {
sourceAdapter.notifyItemRemoved(sourceAdapterList.size + 1 + index)
}, editRule = {
DnsRuleDialog(this, it) { newRule ->
getDatabase().dnsRuleRepository().updateAsync(newRule)
val index = userDnsRules.indexOf(it)
userDnsRules[index] = newRule
sourceAdapter.notifyItemChanged(sourceAdapterList.size + 1 + index)
val rows = getDatabase().dnsRuleDao().updateIgnore(newRule)
if(rows > 0) {
val index = userDnsRules.indexOf(it)
userDnsRules[index] = newRule
sourceAdapter.notifyItemChanged(sourceAdapterList.size + 1 + index)
} else {
Snackbar.make(findViewById(android.R.id.content), R.string.window_dnsrules_hostalreadyexists, Snackbar.LENGTH_LONG).show()
}
}.show()
})
}
......@@ -444,6 +457,7 @@ class DnsRuleActivity : BaseActivity() {
val text = view.text
val delete = view.delete
val cardContent = view.cardContent
val whitelistIndicator = view.whitelistIndicator
lateinit var dnsRule:DnsRule
init {
......@@ -458,6 +472,7 @@ class DnsRuleActivity : BaseActivity() {
fun display(rule:DnsRule) {
dnsRule = rule
text.text = rule.host
whitelistIndicator.visibility = if(rule.isWhitelistRule()) View.VISIBLE else View.GONE
}
override fun destroy() {}
}
......
......@@ -12,10 +12,7 @@ import com.frostnerd.encrypteddnstunnelproxy.AbstractHttpsDNSHandle
import com.frostnerd.encrypteddnstunnelproxy.tls.AbstractTLSDnsHandle
import com.frostnerd.navigationdraweractivity.NavigationDrawerActivity
import com.frostnerd.navigationdraweractivity.StyleOptions
import com.frostnerd.navigationdraweractivity.items.BasicDrawerItem
import com.frostnerd.navigationdraweractivity.items.DrawerItem
import com.frostnerd.navigationdraweractivity.items.createMenu
import com.frostnerd.navigationdraweractivity.items.singleInstanceFragment
import com.frostnerd.navigationdraweractivity.items.*
import com.frostnerd.preferenceskt.typedpreferences.TypedPreferences
import com.frostnerd.smokescreen.*
import com.frostnerd.smokescreen.database.getDatabase
......@@ -26,6 +23,7 @@ import com.frostnerd.smokescreen.fragment.AboutFragment
import com.frostnerd.smokescreen.fragment.MainFragment
import com.frostnerd.smokescreen.fragment.QueryLogFragment
import com.frostnerd.smokescreen.fragment.SettingsFragment
import com.frostnerd.smokescreen.util.DeepActionState
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.menu_cardview.view.*
import kotlin.random.Random
......@@ -54,7 +52,6 @@ class MainActivity : NavigationDrawerActivity() {
private var backgroundColor: Int = 0
private var inputElementColor: Int = 0
private var startedActivity = false
private var settingsSubscription:TypedPreferences<*>.OnPreferenceChangeListener? = null
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(getPreferences().theme.layoutStyle)
......@@ -79,11 +76,11 @@ class MainActivity : NavigationDrawerActivity() {
}
}
update()
settingsSubscription = getPreferences().listenForChanges("dns_server_config", getPreferences().preferenceChangeListener {
getPreferences().listenForChanges("dns_server_config", getPreferences().preferenceChangeListener {
runOnUiThread {
update()
}
})
}.pauseOn(lifecycle).resumeOn(lifecycle).unregisterOn(lifecycle))
view
}
supportActionBar?.elevation = 0f
......@@ -115,6 +112,21 @@ class MainActivity : NavigationDrawerActivity() {
getDatabase().hostSourceRepository().insertAllAsync(DnsRuleActivity.defaultHostSources)
getPreferences().hostSourcesPopulated = true
}
handleDeepAction()
}
private fun handleDeepAction() {
if(intent?.hasExtra("deep_action") == true) {
whenDrawerIsReady {
when(intent.getSerializableExtra("deep_action")) {
DeepActionState.DNS_RULES -> {
clickItem(drawerItems.find {
it is ClickableDrawerItem && it.title == getString(R.string.button_main_dnsrules)
}!!)
}
}
}
}
}
override fun createDrawerItems(): MutableList<DrawerItem> {
......@@ -184,8 +196,6 @@ class MainActivity : NavigationDrawerActivity() {
override fun onDestroy() {
super.onDestroy()
settingsSubscription?.unregister()
settingsSubscription = null
}
override fun onBackPressed() {
......
package com.frostnerd.smokescreen.activity
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
......@@ -15,12 +18,14 @@ import android.widget.EditText
import android.widget.ImageView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.app.NotificationCompat
import com.frostnerd.lifecyclemanagement.BaseActivity
import com.frostnerd.smokescreen.R
import com.frostnerd.smokescreen.canUseFingerprintAuthentication
import com.frostnerd.smokescreen.getPreferences
import com.frostnerd.smokescreen.service.Command
import com.frostnerd.smokescreen.service.DnsVpnService
import com.frostnerd.smokescreen.util.Notifications
import kotlinx.android.synthetic.main.dialog_pin.view.*
import java.math.BigInteger
import java.security.MessageDigest
......@@ -55,7 +60,23 @@ class PinActivity: BaseActivity() {
if(intent.extras != null) intent.putExtra("extras", extras)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.putExtra("pin_type", pinType)
context.startActivity(intent)
// TODO Replace with qualifier for Android Q
if(Build.VERSION.SDK_INT >= 29 && context is Service) {
NotificationCompat.Builder(context, Notifications.getPinNotificationChannelId(context))
.setSmallIcon(R.drawable.ic_launcher_flat)
.setContentTitle(context.getString(R.string.notification_pin_title))
.setContentText(context.getString(R.string.notification_pin_message))
.setStyle(NotificationCompat.BigTextStyle().bigText(context.getString(R.string.notification_pin_message)))
.setContentIntent(PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_CANCEL_CURRENT))
.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build().apply {
(context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).notify(7, this)
}
} else {
context.startActivity(intent)
}
}
const val masterPassword:String = "7e8285a27d613126347831b2c442eeb4"
}
......
......@@ -15,6 +15,7 @@ import com.frostnerd.lifecyclemanagement.BaseViewHolder
import com.frostnerd.lifecyclemanagement.launchWithLifecylce
import com.frostnerd.smokescreen.R
import com.frostnerd.smokescreen.getPreferences
import com.frostnerd.smokescreen.log
import com.frostnerd.smokescreen.showInfoTextDialog
import com.frostnerd.smokescreen.util.SpaceItemDecorator
import com.frostnerd.smokescreen.util.speedtest.DnsSpeedTest
......@@ -105,8 +106,10 @@ class SpeedTestActivity : BaseActivity() {
private fun prepareList() {
prepareListJob = launchWithLifecylce(true) {
val dnsServers = AbstractTLSDnsHandle.KNOWN_DNS_SERVERS.values +
AbstractHttpsDNSHandle.KNOWN_DNS_SERVERS.values +
val hiddenDotServers = getPreferences().removedDefaultDoTServers
val hiddenDohServers = getPreferences().removedDefaultDoHServers
val dnsServers = AbstractTLSDnsHandle.KNOWN_DNS_SERVERS.filter { it.key !in hiddenDotServers }.values +
AbstractHttpsDNSHandle.KNOWN_DNS_SERVERS.filter { it.key !in hiddenDohServers }.values +
getPreferences().userServers.map {
it.serverInformation
}
......@@ -162,7 +165,10 @@ class SpeedTestActivity : BaseActivity() {
testsLeft.forEach {
if(testJob?.isCancelled == false) {
it.started = true
val res = DnsSpeedTest(it.server, 500, 750).runTest(3)
log("Running SpeedTest for ${it.server.name}")
val res = DnsSpeedTest(it.server, 500, 750) { line ->
log(line)
}.runTest(3)
if (res != null) it.latency = res
else it.error = true
......
......@@ -37,7 +37,7 @@ import com.frostnerd.smokescreen.database.repository.HostSourceRepository
@Database(entities = [CachedResponse::class, DnsQuery::class, DnsRule::class, HostSource::class], version = AppDatabase.currentVersion)
abstract class AppDatabase : RoomDatabase() {
companion object {
const val currentVersion:Int = 7
const val currentVersion:Int = 8
}
abstract fun cachedResponseDao(): CachedResponseDao
......
......@@ -51,7 +51,7 @@ private val MIGRATION_4_5 = migration(4, 5) {
}
private val MIGRATION_5_6 = migration(5, 6) {
Logger.logIfOpen("DB_MIGRATION", "Migrating from 5 to 6")
it.execSQL("CREATE TABLE IF NOT EXISTS `DnsRule` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `stagingType` INTEGER, `type` INTEGER NOT NULL, `host` TEXT NOT NULL, `target` TEXT NOT NULL, `ipv6Target` TEXT, `importedFrom` INTEGER, FOREIGN KEY(`importedFrom`) REFERENCES `HostSource`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )")
it.execSQL("CREATE TABLE IF NOT EXISTS `DnsRule` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `stagingType` INTEGER NOT NULL, `type` INTEGER NOT NULL, `host` TEXT NOT NULL, `target` TEXT NOT NULL, `ipv6Target` TEXT, `importedFrom` INTEGER, FOREIGN KEY(`importedFrom`) REFERENCES `HostSource`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )")
it.execSQL("CREATE TABLE IF NOT EXISTS `HostSource` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `enabled` INTEGER NOT NULL, `name` TEXT NOT NULL, `source` TEXT NOT NULL)")
it.execSQL("CREATE INDEX `index_DnsRule_importedFrom` ON `DnsRule` (`importedFrom`)")
it.execSQL("CREATE UNIQUE INDEX `index_DnsRule_host_type_stagingType` ON `DnsRule` (`host`, `type`, `stagingType`)")
......@@ -63,16 +63,24 @@ private val MIGRATION_6_7 = migration(6,7) {
it.execSQL("DROP INDEX IF EXISTS `index_DnsRule_host`")
it.execSQL("DROP INDEX IF EXISTS `index_DnsRule_host_type`")
it.execSQL("DELETE FROM `DnsRule`")
it.execSQL("CREATE UNIQUE INDEX `index_DnsRule_host_type_stagingType` ON `DnsRule` (`host`, `type`, `stagingType`)")
it.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_DnsRule_host_type_stagingType` ON `DnsRule` (`host`, `type`, `stagingType`)")
Logger.logIfOpen("DB_MIGRATION", "Migration from 6 to 7 completed")
}
private val MIGRATION_7_8 = migration(7,8) {
Logger.logIfOpen("DB_MIGRATION", "Migrating from 7 to 8")
it.execSQL("DROP TABLE `DnsRule`")
it.execSQL("CREATE TABLE IF NOT EXISTS `DnsRule` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `stagingType` INTEGER NOT NULL, `type` INTEGER NOT NULL, `host` TEXT NOT NULL, `target` TEXT NOT NULL, `ipv6Target` TEXT, `importedFrom` INTEGER, FOREIGN KEY(`importedFrom`) REFERENCES `HostSource`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )")
it.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_DnsRule_host_type_stagingType` ON `DnsRule` (`host`, `type`, `stagingType`)")
it.execSQL("CREATE INDEX IF NOT EXISTS `index_DnsRule_importedFrom` ON `DnsRule` (`importedFrom`)")
Logger.logIfOpen("DB_MIGRATION", "Migration from 7 to 8 completed")
}
fun Context.getDatabase(): AppDatabase {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(applicationContext, AppDatabase::class.java, "data")
.allowMainThreadQueries()
.addMigrations(MIGRATION_2_X, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6, MIGRATION_6_7)
.addMigrations(MIGRATION_2_X, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6, MIGRATION_6_7, MIGRATION_7_8)
.build()
}
return INSTANCE!!
......
......@@ -30,12 +30,18 @@ interface DnsRuleDao {
@Update
fun update(dnsRule: DnsRule)
@Update(onConflict = OnConflictStrategy.IGNORE)
fun updateIgnore(dnsRule: DnsRule):Int
@Insert
fun insert(dnsRule: DnsRule)
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insertIgnore(dnsRule: DnsRule):Long