Commit 227c4bea authored by Daniel Wolf's avatar Daniel Wolf
Browse files

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

parents 0fc505ec 9778c56a
......@@ -45,8 +45,4 @@ captures/
libs/
libs/**
.idea/markdown-navigator-enh.xml
.idea/markdown-navigator.xml
.idea/navEditor.xml
\ No newline at end of file
libs/**
\ No newline at end of file
......@@ -46,7 +46,7 @@ There are two options on how to use the DNS rules:<br>
You can either define your own rules - for example to block single hosts - or import *rule sources* which contain a list of rules.<br><br>
There are multiple lists maintained by independent people you can use in Nebulo.
They cover different topics, from blocking ads, tracking to blocking porn or social media.<br>
I recommend checking out [Energized](energized.pro).
I recommend checking out [Energized](https://energized.pro).
It has multiple types of lists, covering use cases mentioned above.
If you have the F-Droid version the Energized lists are already added as sources.
......
......@@ -12,13 +12,16 @@ android {
applicationId "com.frostnerd.smokescreen"
minSdkVersion 21
targetSdkVersion 30
versionCode 74
versionName "2.0.3"
versionCode 75
versionName "2.0.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
def sentryDSN = String.valueOf(getSystemVariableOrDefault("NEBULO_SENTRY_DSN", "dummy"))
def sentryConfigServer = String.valueOf(getSystemVariableOrDefault("NEBULO_SENTRY_CONFIGSERVER", "dummy"))
buildConfigField("Boolean", "FROM_CI", String.valueOf(getSystemVariableOrDefault("CI_COMMIT_SHORT_SHA", "") != ""))
buildConfigField("String", "COMMIT_HASH", '"' + getGitCommitHash() + '"')
buildConfigField("String", "SENTRY_DSN", '""')
buildConfigField("String", "SENTRY_DSN", '"' + sentryDSN+ '"') // A valid Sentry DSN, or "dummy"
buildConfigField("String", "SENTRY_DSN_CONFIGSERVER", '"' + sentryConfigServer + '"') // A host which returns a valid Sentry DSN on GET, or "dummy". If both are dummy Sentry is disabled.
buildConfigField("Boolean", "SHOW_DOQ", 'false')
buildConfigField("Boolean", "SHOW_INTRO", 'false')
buildConfigField("Boolean", "IN_APP_UPDATES", "false")
......@@ -99,7 +102,7 @@ android {
matchingFallbacks = ['default']
dimension "version"
versionNameSuffix "-adblock"
versionCode 75
versionCode 76
}
normal {
matchingFallbacks = ['default']
......@@ -147,10 +150,10 @@ dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'
implementation 'com.frostnerd.utilskt:lifecycle:1.2.0'
implementation 'com.frostnerd.utilskt:lifecycle:1.2.1'
implementation 'com.frostnerd.utilskt:preferences:1.5.30' // https://git.frostnerd.com/AndroidUtils/preferenceskt
implementation 'com.frostnerd.utilskt:navigationdraweractivity:1.4.0' // https://git.frostnerd.com/AndroidUtils/navigationdraweractivity
implementation 'com.frostnerd.utilskt:encrypteddnstunnelproxy:2.1.20' // https://git.frostnerd.com/AndroidUtils/encrypteddnstunnelproxy
implementation 'com.frostnerd.utilskt:navigationdraweractivity:1.4.2' // https://git.frostnerd.com/AndroidUtils/navigationdraweractivity
implementation 'com.frostnerd.utilskt:encrypteddnstunnelproxy:2.1.21' // https://git.frostnerd.com/AndroidUtils/encrypteddnstunnelproxy
implementation 'com.frostnerd.utilskt:general:1.0.25' // https://git.frostnerd.com/AndroidUtils/generalkt
implementation 'com.frostnerd.utilskt:adapters:1.2.0' // https://git.frostnerd.com/AndroidUtils/Adapters
......@@ -169,9 +172,8 @@ dependencies {
implementation 'io.sentry:sentry-android:3.2.0'
implementation 'com.github.jorgecastilloprz:fabprogresscircle:1.01@aar'
implementation 'com.squareup.leakcanary:leaksentry:2.0-alpha-3'
leakCanaryImplementation 'com.squareup.leakcanary:leakcanary-android:2.5'
leakCanaryImplementation 'com.squareup.leakcanary:leakcanary-android:2.6'
implementation "com.squareup.okhttp3:okhttp:4.9.0"
implementation 'com.github.AppIntro:AppIntro:6.0.0'
......
......@@ -11,7 +11,8 @@
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<uses-permission
android:name="android.permission.INTERACT_ACROSS_USERS"
tools:ignore="ProtectedPermissions" />
......
......@@ -38,7 +38,6 @@ import com.frostnerd.smokescreen.util.proxy.IpTablesPacketRedirector
import io.sentry.NoOpLogger
import io.sentry.android.core.BuildInfoProvider
import io.sentry.android.core.util.RootChecker
import leakcanary.LeakSentry
import java.net.Inet4Address
import java.net.Inet6Address
import java.net.InetAddress
......@@ -63,6 +62,7 @@ import java.util.logging.Level
* You can contact the developer at daniel.wolf@frostnerd.com.
*/
@Suppress("DEPRECATION")
fun Context.canUseFingerprintAuthentication(): Boolean {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false
val mgr = getSystemService(Context.FINGERPRINT_SERVICE) as? FingerprintManager
......@@ -73,6 +73,7 @@ fun Context.canUseFingerprintAuthentication(): Boolean {
return true
}
@Suppress("unused")
fun Context.registerReceiver(intentFilter: IntentFilter, receiver: (intent: Intent?) -> Unit): BroadcastReceiver {
val actualReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
......@@ -158,6 +159,7 @@ fun AppCompatActivity.registerLocalReceiver(
mgr.registerReceiver(actualReceiver, filter)
if(unregisterOnDestroy) lifecycle.addObserver(object:LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
@Suppress("unused")
fun onDestroy() {
mgr.unregisterReceiver(actualReceiver)
}
......@@ -399,7 +401,7 @@ private fun createHttpsUpstreamAddress(url: String): HttpsUpstreamAddress {
}
private fun createTlsUpstreamAddress(host: String): TLSUpstreamAddress {
var parsedHost = ""
val parsedHost:String
var port: Int? = null
if (host.contains(":")) {
parsedHost = host.split(":")[0]
......@@ -410,18 +412,6 @@ private fun createTlsUpstreamAddress(host: String): TLSUpstreamAddress {
else TLSUpstreamAddress(parsedHost)
}
fun LeakSentry.watchIfEnabled(watchedInstance: Any) {
if(BuildConfig.LEAK_DETECTION) {
refWatcher.watch(watchedInstance)
}
}
fun LeakSentry.watchIfEnabled(watchedInstance: Any, name:String) {
if(BuildConfig.LEAK_DETECTION) {
refWatcher.watch(watchedInstance, name)
}
}
fun String.equalsAny(vararg options:String, ignoreCase:Boolean = false):Boolean {
return options.any {
it.equals(this, ignoreCase)
......
......@@ -11,7 +11,6 @@ import io.sentry.Sentry
import io.sentry.SentryEvent
import io.sentry.SentryLevel
import io.sentry.protocol.Message
import leakcanary.LeakSentry
import java.io.*
import java.text.SimpleDateFormat
import java.util.*
......@@ -65,7 +64,6 @@ private fun Context.logErrorSentry(e: Throwable, extras: Map<String, String>? =
this.message = e.message
}
level = SentryLevel.ERROR
setExtra("retainedInstanceCount", LeakSentry.refWatcher.retainedInstanceCount)
})
} else if (getPreferences().crashreportingType == Crashreporting.FULL && extras != null && extras.isNotEmpty()) {
log("Sending exception with extras")
......@@ -78,7 +76,6 @@ private fun Context.logErrorSentry(e: Throwable, extras: Map<String, String>? =
extras.forEach { (key, value) ->
setTag(key, value)
}
setExtra("retainedInstanceCount", LeakSentry.refWatcher.retainedInstanceCount)
})
} else {
log("Sending exception to Sentry without extras")
......@@ -121,7 +118,7 @@ fun Context.log(e: Throwable, extras: Map<String, String>? = null) {
"${Logger.logFileNameTimeStampFormatter.format(System.currentTimeMillis())}.err"
)
if (errorFile.createNewFile()) {
if (errorFile.tryCreateNewFile()) {
val writer = BufferedWriter(FileWriter(errorFile, false))
writer.write("App version: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE}, Commit: ${BuildConfig.COMMIT_HASH})\n")
writer.write("Android SDK version: ${Build.VERSION.SDK_INT} (${Build.VERSION.RELEASE} - ${Build.VERSION.CODENAME})\n")
......@@ -141,7 +138,7 @@ fun Context.closeLogger() {
fun Context.deleteAllLogs() {
if (Logger.isOpen())
Logger.getInstance(this).destroy()
Logger.getLogDir(this).listFiles().forEach {
Logger.getLogDir(this).listFiles()!!.forEach {
it.delete()
}
}
......@@ -181,7 +178,7 @@ class Logger private constructor(context: Context) {
"${id}_${logFileNameTimeStampFormatter.format(System.currentTimeMillis())}.log"
)
logDir.mkdirs()
logFile.createNewFile()
logFile.tryCreateNewFile()
fileWriter = BufferedWriter(FileWriter(logFile, false))
log("App version: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})")
......@@ -309,8 +306,12 @@ class Logger private constructor(context: Context) {
if (printToConsole) {
(oldSystemOut ?: System.out).println(textBuilder)
}
fileWriter.write(textBuilder.toString())
fileWriter.flush()
try {
fileWriter.write(textBuilder.toString())
fileWriter.flush()
} catch (ex:Throwable) {
}
}
}
}
......@@ -325,7 +326,7 @@ class Logger private constructor(context: Context) {
"${id}_${logFileNameTimeStampFormatter.format(System.currentTimeMillis())}.err"
)
if (errorFile.createNewFile()) {
if (errorFile.tryCreateNewFile()) {
val writer = BufferedWriter(FileWriter(errorFile, false))
writer.write("App version: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})\n")
writer.write("Android SDK version: ${Build.VERSION.SDK_INT} (${Build.VERSION.RELEASE} - ${Build.VERSION.CODENAME})\n")
......@@ -343,6 +344,14 @@ class Logger private constructor(context: Context) {
}
}
fun File.tryCreateNewFile():Boolean {
return try {
createNewFile()
} catch (ex:Throwable) {
false
}
}
fun Context.zipAllLogFiles(): File? {
val dir = Logger.getLogDir(this)
if (!dir.canWrite() || !dir.canRead()) return null
......@@ -351,7 +360,7 @@ fun Context.zipAllLogFiles(): File? {
if (zipFile.exists() && (!zipFile.canRead() || !zipFile.canWrite())) return null
if (zipFile.exists()) zipFile.delete()
var filesToBeZipped = dir.listFiles()
var filesToBeZipped = dir.listFiles()!!
val dest = FileOutputStream(zipFile)
val out = ZipOutputStream(BufferedOutputStream(dest))
val buffer = ByteArray(2048)
......
......@@ -24,16 +24,13 @@ import io.sentry.Sentry
import io.sentry.SentryOptions
import io.sentry.android.core.*
import io.sentry.protocol.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import leakcanary.LeakSentry
import okhttp3.*
import org.minidns.dnsmessage.DnsMessage
import org.minidns.dnsmessage.Question
import org.minidns.record.A
import org.minidns.record.AAAA
import org.minidns.record.Record
import java.net.InetAddress
import java.io.IOException
import java.util.*
import kotlin.system.exitProcess
......@@ -68,15 +65,15 @@ class SmokeScreen : Application() {
else {
context.log("Using fallback server: $to")
val configs = to.serverConfigurations.values
AddressCreator.globalResolve = {
val responsesIpv4 = configs.random().query(Question(it, Record.TYPE.A))?.takeIf {
AddressCreator.globalResolve = { domain ->
val responsesIpv4 = configs.random().query(Question(domain, Record.TYPE.A))?.takeIf {
it.responseCode == DnsMessage.RESPONSE_CODE.NO_ERROR
}?.answerSection?.map {
it.payload as A
}?.map {
it.inetAddress
}
val responsesIpv6 = configs.random().query(Question(it, Record.TYPE.AAAA))?.takeIf {
val responsesIpv6 = configs.random().query(Question(domain, Record.TYPE.AAAA))?.takeIf {
it.responseCode == DnsMessage.RESPONSE_CODE.NO_ERROR
}?.answerSection?.map {
it.payload as AAAA
......@@ -135,16 +132,14 @@ class SmokeScreen : Application() {
}
override fun onCreate() {
if(!BuildConfig.LEAK_DETECTION) LeakSentry.config = LeakSentry.config.copy(enabled = false)
initSentry()
defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
Thread.setDefaultUncaughtExceptionHandler(customUncaughtExceptionHandler)
super.onCreate()
log("Application created.")
LeakSentry.watchIfEnabled(this)
handleFallbackDns()
loadKnownDNSServers()
AbstractQuicDnsHandle.installProvider(this, {})
AbstractQuicDnsHandle.installProvider(this) {}
}
private fun handleFallbackDns() {
......@@ -175,75 +170,122 @@ class SmokeScreen : Application() {
}
fun initSentry(forceStatus: Status = Status.NONE) {
if (!BuildConfig.DEBUG && BuildConfig.SENTRY_DSN != "dummy") {
log("Sentry will be initialized.")
GlobalScope.launch(Dispatchers.IO) {
log("Initializing Sentry.")
sentryReady = false
try {
val hostName = InetAddress.getLocalHost().hostName
if(!hostName.startsWith("mars-sandbox", true)) {
val enabledType = getPreferences().crashreportingType
if (forceStatus != Status.DATASAVING && (enabledType == Crashreporting.FULL || forceStatus == Status.ENABLED)) {
// Enable Sentry in full mode
// This passes some device-related data, but nothing which allows user actions to be tracked across the app
// Info: Some data is attached by the AndroidEventBuilderHelper class, which is present by default
val enabledType = getPreferences().crashreportingType
if (forceStatus == Status.NONE &&
enabledType == Crashreporting.OFF) return
log("Maybe initializing Sentry")
getSentryDSN { resolvedDSN ->
log("Initializing Sentry.")
sentryReady = false
try {
if (sentryReady) {
log("Reinitializing Sentry with new DSN")
SentryAndroid.init(this@SmokeScreen) {
it.dsn = resolvedDSN
}
} else {
if (forceStatus != Status.DATASAVING && (enabledType == Crashreporting.FULL || forceStatus == Status.ENABLED)) {
// Enable Sentry in full mode
// This passes some device-related data, but nothing which allows user actions to be tracked across the app
// Info: Some data is attached by the AndroidEventBuilderHelper class, which is present by default
SentryAndroid.init(this@SmokeScreen) {
it.dsn = BuildConfig.SENTRY_DSN
}
Sentry.setUser(User().apply {
this.username = getPreferences().crashReportingUUID
})
Sentry.setTag("user.language", Locale.getDefault().displayLanguage)
Sentry.setTag(
"app.database_version",
AppDatabase.currentVersion.toString()
)
Sentry.setTag(
"app.dns_server_name",
getPreferences().dnsServerConfig.name
)
Sentry.setTag(
"app.dns_server_primary",
getPreferences().dnsServerConfig.servers[0].address.formatToString()
)
Sentry.setTag(
"app.dns_server_secondary",
getPreferences().dnsServerConfig.servers.getOrNull(1)?.address?.formatToString()
?: ""
)
Sentry.setTag(
"app.installer_package",
packageManager.getInstallerPackageName(packageName) ?: ""
)
Sentry.setTag("richdata", "true")
Sentry.setTag("app.fromCi", BuildConfig.FROM_CI.toString())
Sentry.setTag("app.commit", BuildConfig.COMMIT_HASH)
sentryReady = true
} else if (enabledType == Crashreporting.MINIMAL || forceStatus == Status.DATASAVING) {
// Inits Sentry in datasaving mode
// Only data absolutely necessary is transmitted (Android version, app version).
// Only crashes will be reported, no regular events.
SentryAndroid.init(this@SmokeScreen) {
it.dsn = BuildConfig.SENTRY_DSN
setupSentryForDatasaving(it)
}
Sentry.setUser(User().apply {
this.username = "anon-" + BuildConfig.VERSION_CODE
})
Sentry.setTag("richdata", "false")
Sentry.setTag("dist", BuildConfig.VERSION_CODE.toString())
Sentry.setTag("app.commit", BuildConfig.COMMIT_HASH)
Sentry.setTag("app.fromCi", BuildConfig.FROM_CI.toString())
sentryReady = true
SentryAndroid.init(this@SmokeScreen) {
it.dsn = resolvedDSN
}
Sentry.setUser(User().apply {
this.username = getPreferences().crashReportingUUID
})
Sentry.setTag("user.language", Locale.getDefault().displayLanguage)
Sentry.setTag(
"app.database_version",
AppDatabase.currentVersion.toString()
)
Sentry.setTag(
"app.dns_server_name",
getPreferences().dnsServerConfig.name
)
Sentry.setTag(
"app.dns_server_primary",
getPreferences().dnsServerConfig.servers[0].address.formatToString()
)
Sentry.setTag(
"app.dns_server_secondary",
getPreferences().dnsServerConfig.servers.getOrNull(1)?.address?.formatToString()
?: ""
)
Sentry.setTag(
"app.installer_package",
packageManager.getInstallerPackageName(packageName) ?: ""
)
Sentry.setTag("richdata", "true")
Sentry.setTag("app.fromCi", BuildConfig.FROM_CI.toString())
Sentry.setTag("app.commit", BuildConfig.COMMIT_HASH)
sentryReady = true
} else if (enabledType == Crashreporting.MINIMAL || forceStatus == Status.DATASAVING) {
// Inits Sentry in datasaving mode
// Only data absolutely necessary is transmitted (Android version, app version).
// Only crashes will be reported, no regular events.
SentryAndroid.init(this@SmokeScreen) {
it.dsn = resolvedDSN
setupSentryForDatasaving(it)
}
Sentry.setUser(User().apply {
this.username = "anon-" + BuildConfig.VERSION_CODE
})
Sentry.setTag("richdata", "false")
Sentry.setTag("dist", BuildConfig.VERSION_CODE.toString())
Sentry.setTag("app.commit", BuildConfig.COMMIT_HASH)
Sentry.setTag("app.fromCi", BuildConfig.FROM_CI.toString())
sentryReady = true
}
} catch(ex:Throwable) {
ex.printStackTrace()
}
log("Sentry ready.")
} catch (ex: Throwable) {
log("Creating Sentry errored")
log(ex)
}
}
}
private fun getSentryDSN(then:(dsn:String) -> Unit) {
if(BuildConfig.DEBUG) return
try {
val primaryDSN = BuildConfig.SENTRY_DSN
val configServer = BuildConfig.SENTRY_DSN_CONFIGSERVER
if(primaryDSN.contains("@")) then(primaryDSN)
else log("Primary Sentry DSN not set, maybe retrieving from server")
if(configServer.isNotBlank() && configServer.startsWith("http") && !configServer.contains("@")) {
log("Dynamically retrieving Sentry DSN from $configServer")
val request = Request.Builder().url(configServer).build()
OkHttpClient.Builder().build().newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
log("Sentry DSN retrieval failed with error: ${e.message}")
}
override fun onResponse(call: Call, response: Response) {
println("RESPONSE")
if (!response.isSuccessful) {
log("Sentry DSN retrieval failed with status ${response.code}")
}
val retrievedDSN = response.body?.string()?.trim()
if (retrievedDSN.isNullOrBlank() || !retrievedDSN.contains("@") || !retrievedDSN.startsWith(
"http"
)
) {
log("Sentry DSN retrieval returned invalid DSN '$retrievedDSN'.")
} else {
if (retrievedDSN != primaryDSN) {
log("Sentry DSN successfuly resolved to '$retrievedDSN'")
then(retrievedDSN)
} else log("Retrieved Sentry DSN is the same as configured DSN, not re-configuring")
}
}
})
}
} catch (ex:Throwable) {
log("Getting Sentry DSN errorerd")
log(ex)
}
}
......
......@@ -5,9 +5,12 @@ import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.net.*
import android.os.Build
import android.os.Bundle
import android.os.PowerManager
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import com.frostnerd.general.service.isServiceRunning
import com.frostnerd.lifecyclemanagement.launchWithLifecycle
import com.frostnerd.navigationdraweractivity.NavigationDrawerActivity
......@@ -92,7 +95,7 @@ class MainActivity : NavigationDrawerActivity() {
setTheme(getPreferences().theme.layoutStyle)
super.onCreate(savedInstanceState)
Notifications.createAllChannels(this)
setCardView { viewParent, suggestedHeight ->
setCardView { viewParent, _ ->
val view = layoutInflater.inflate(R.layout.menu_cardview, viewParent, false)
val update = {
launchWithLifecycle {
......@@ -209,7 +212,9 @@ class MainActivity : NavigationDrawerActivity() {
!getPreferences().ignoreServiceKilled &&
getPreferences().vpnLaunchLastVersion == BuildConfig.VERSION_CODE) {
getPreferences().vpnServiceState = VpnServiceState.STOPPED
BatteryOptimizationInfoDialog(this).show()
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M|| !(getSystemService(POWER_SERVICE) as PowerManager).isIgnoringBatteryOptimizations(packageName)) {
BatteryOptimizationInfoDialog(this).show()
}
}
registerLocalReceiver(listOf(BROADCAST_RELOAD_MENU), true) {
reloadMenuItems()
......@@ -279,11 +284,11 @@ class MainActivity : NavigationDrawerActivity() {
override fun createDrawerItems(): MutableList<DrawerItem> {
return createMenu {
fragmentItem(getString(R.string.menu_main),
iconLeft = getDrawable(R.drawable.ic_menu_dnsoverhttps),
iconLeft = ContextCompat.getDrawable(this@MainActivity, R.drawable.ic_menu_dnsoverhttps),
fragmentCreator = singleInstanceFragment { MainFragment() }
)
fragmentItem(getString(R.string.menu_settings),
iconLeft = getDrawable(R.drawable.ic_menu_settings),
iconLeft = ContextCompat.getDrawable(this@MainActivity, R.drawable.ic_menu_settings),
fragmentCreator = singleInstanceFragment { args ->
SettingsOverviewFragment().also {
it.arguments = args
......@@ -292,7 +297,7 @@ class MainActivity : NavigationDrawerActivity() {
if (getPreferences().queryLoggingEnabled) {
divider()
fragmentItem(getString(R.string.menu_querylogging),
iconLeft = getDrawable(R.drawable.ic_eye),
iconLeft = ContextCompat.getDrawable(this@MainActivity, R.drawable.ic_eye),
fragmentCreator = {
QueryLogFragment()
})
......@@ -300,7 +305,7 @@ class MainActivity : NavigationDrawerActivity() {
}
divider()
clickableItem(getString(R.string.menu_create_shortcut),
iconLeft = getDrawable(R.drawable.ic_external_link),
iconLeft = ContextCompat.getDrawable(this@MainActivity, R.drawable.ic_external_link),
onLongClick = null,
onSimpleClick = { _, _, _ ->
ServerChoosalDialog(this@MainActivity, onEntrySelected = {
......@@ -309,14 +314,14 @@ class MainActivity : NavigationDrawerActivity() {
false
})
fragmentItem(getString(R.string.button_main_dnsrules),
iconLeft = getDrawable(R.drawable.ic_view_list),
iconLeft = ContextCompat.getDrawable(this@MainActivity, R.drawable.ic_view_list),
fragmentCreator = {
DnsRuleFragment()
})
divider()
if (isPackageInstalled(this@MainActivity, "com.android.vending")) {
clickableItem(getString(R.string.menu_rate),
iconLeft = getDrawable(R.drawable.ic_star),
iconLeft = ContextCompat.getDrawable(this@MainActivity, R.drawable.ic_star),
onLongClick = null,
onSimpleClick = { _, _, _ ->
AlertDialog.Builder(this@MainActivity, getPreferences().theme.dialogStyle)
......@@ -333,7 +338,7 @@ class MainActivity : NavigationDrawerActivity() {
}
if (isPackageInstalled(this@MainActivity, "org.fdroid.fdroid")) {
clickableItem(getString(R.string.menu_show_on_fdroid),
iconLeft = getDrawable(R.drawable.ic_adb),
iconLeft = ContextCompat.getDrawable(this@MainActivity, R.drawable.ic_adb),
onLongClick = null,
onSimpleClick = { _, _, _ ->
startActivity(
......@@ -347,13 +352,13 @@ class MainActivity : NavigationDrawerActivity() {
)
}
fragmentItem(getString(R.string.menu_about),
iconLeft = getDrawable(R.drawable.ic_info),
iconLeft = ContextCompat.getDrawable(this@MainActivity, R.drawable.ic_info),
fragmentCreator = singleInstanceFragment { AboutFragment() })
}
}
override fun onBackPressed() {
val fragment = currentFragment
val fragment = supportFragmentManager.findFragmentById