diff --git a/app/build.gradle b/app/build.gradle index 1a7727fd..7fe63765 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -247,8 +247,8 @@ dependencies { fullImplementation 'com.github.kirich1409:viewbindingpropertydelegate-noreflection:1.5.9' // from: https://jitpack.io/#celzero/firestack - download 'com.github.celzero:firestack:1f812ec9e6@aar' - implementation 'com.github.celzero:firestack:1f812ec9e6@aar' + download 'com.github.celzero:firestack:dd04f72717@aar' + implementation 'com.github.celzero:firestack:dd04f72717@aar' // Work manager implementation('androidx.work:work-runtime-ktx:2.9.0') { diff --git a/app/src/full/java/com/celzero/bravedns/adapter/AppWiseDomainsAdapter.kt b/app/src/full/java/com/celzero/bravedns/adapter/AppWiseDomainsAdapter.kt index e590b05b..ce5fe747 100644 --- a/app/src/full/java/com/celzero/bravedns/adapter/AppWiseDomainsAdapter.kt +++ b/app/src/full/java/com/celzero/bravedns/adapter/AppWiseDomainsAdapter.kt @@ -18,7 +18,6 @@ package com.celzero.bravedns.adapter import Logger import Logger.LOG_TAG_UI import android.content.Context -import android.content.res.ColorStateList import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -33,8 +32,10 @@ import com.celzero.bravedns.data.AppConnection import com.celzero.bravedns.databinding.ListItemAppDomainDetailsBinding import com.celzero.bravedns.service.DomainRulesManager import com.celzero.bravedns.ui.bottomsheet.AppDomainRulesBottomSheet -import com.celzero.bravedns.util.UIUtils.fetchColor +import com.celzero.bravedns.util.UIUtils +import com.celzero.bravedns.util.Utilities import com.celzero.bravedns.util.Utilities.removeBeginningTrailingCommas +import kotlin.math.log2 class AppWiseDomainsAdapter( val context: Context, @@ -46,6 +47,9 @@ class AppWiseDomainsAdapter( ), AppDomainRulesBottomSheet.OnBottomSheetDialogFragmentDismiss { + private var maxValue: Int = 0 + private var minPercentage: Int = 100 + companion object { private val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { @@ -90,6 +94,24 @@ class AppWiseDomainsAdapter( holder.update(appConnection) } + private fun calculatePercentage(c: Double): Int { + val value = (log2(c) * 100).toInt() + // maxValue will be based on the count returned by db query (order by count desc) + if (value > maxValue) { + maxValue = value + } + return if (maxValue == 0) { + 0 + } else { + val percentage = (value * 100 / maxValue) + // minPercentage is used to show the progress bar when the percentage is 0 + if (percentage < minPercentage && percentage != 0) { + minPercentage = percentage + } + percentage + } + } + inner class ConnectionDetailsViewHolder(private val b: ListItemAppDomainDetailsBinding) : RecyclerView.ViewHolder(b.root) { fun update(conn: AppConnection) { @@ -97,22 +119,23 @@ class AppWiseDomainsAdapter( setupClickListeners(conn) } - private fun displayTransactionDetails(appConnection: AppConnection) { - b.acdCount.text = appConnection.count.toString() - b.acdDomain.text = appConnection.appOrDnsName - if (appConnection.ipAddress.isNotEmpty()) { + private fun displayTransactionDetails(conn: AppConnection) { + b.acdCount.text = conn.count.toString() + b.acdDomain.text = conn.appOrDnsName + b.acdFlag.text = conn.flag + if (conn.ipAddress.isNotEmpty()) { b.acdIpAddress.visibility = View.VISIBLE - b.acdIpAddress.text = beautifyIpString(appConnection.ipAddress) + b.acdIpAddress.text = beautifyIpString(conn.ipAddress) } else { b.acdIpAddress.visibility = View.GONE } - updateStatusUi(appConnection.uid, appConnection.appOrDnsName) + updateStatusUi(conn) } - private fun setupClickListeners(appConn: AppConnection) { + private fun setupClickListeners(conn: AppConnection) { b.acdContainer.setOnClickListener { // open bottom sheet to apply domain/ip rules - openBottomSheet(appConn) + openBottomSheet(conn) } } @@ -141,52 +164,40 @@ class AppWiseDomainsAdapter( return removeBeginningTrailingCommas(d).replace(",,", ",").replace(",", ", ") } - private fun updateStatusUi(uid: Int, domain: String?) { - if (domain == null) { - b.acdFlag.text = context.getString(R.string.ci_no_rule_initial) + private fun updateStatusUi(conn: AppConnection) { + if (conn.appOrDnsName.isNullOrEmpty()) { + b.progress.visibility = View.GONE return } - - val status = DomainRulesManager.getDomainRule(domain, uid) + val status = DomainRulesManager.getDomainRule(conn.appOrDnsName, uid) when (status) { DomainRulesManager.Status.NONE -> { - b.acdFlag.text = context.getString(R.string.ci_no_rule_initial) - } - DomainRulesManager.Status.BLOCK -> { - b.acdFlag.text = context.getString(R.string.ci_blocked_initial) - } - DomainRulesManager.Status.TRUST -> { - b.acdFlag.text = context.getString(R.string.ci_trust_initial) - } - } - - // returns the text and background color for the button - val t = getToggleBtnUiParams(status) - b.acdFlag.setTextColor(t.txtColor) - b.acdFlag.backgroundTintList = ColorStateList.valueOf(t.bgColor) - } - - private fun getToggleBtnUiParams(id: DomainRulesManager.Status): ToggleBtnUi { - return when (id) { - DomainRulesManager.Status.NONE -> { - ToggleBtnUi( - fetchColor(context, R.attr.chipTextNeutral), - fetchColor(context, R.attr.chipBgColorNeutral) + b.progress.setIndicatorColor( + UIUtils.fetchToggleBtnColors(context, R.color.chipTextNeutral) ) } DomainRulesManager.Status.BLOCK -> { - ToggleBtnUi( - fetchColor(context, R.attr.chipTextNegative), - fetchColor(context, R.attr.chipBgColorNegative) + b.progress.setIndicatorColor( + UIUtils.fetchToggleBtnColors(context, R.color.accentBad) ) } DomainRulesManager.Status.TRUST -> { - ToggleBtnUi( - fetchColor(context, R.attr.chipTextPositive), - fetchColor(context, R.attr.chipBgColorPositive) + b.progress.setIndicatorColor( + UIUtils.fetchToggleBtnColors(context, R.color.accentGood) ) } } + + var p = calculatePercentage(conn.count.toDouble()) + if (p == 0) { + p = minPercentage / 2 + } + + if (Utilities.isAtleastN()) { + b.progress.setProgress(p, true) + } else { + b.progress.progress = p + } } } diff --git a/app/src/full/java/com/celzero/bravedns/adapter/AppWiseIpsAdapter.kt b/app/src/full/java/com/celzero/bravedns/adapter/AppWiseIpsAdapter.kt index d65e83fa..95f3c86d 100644 --- a/app/src/full/java/com/celzero/bravedns/adapter/AppWiseIpsAdapter.kt +++ b/app/src/full/java/com/celzero/bravedns/adapter/AppWiseIpsAdapter.kt @@ -18,7 +18,6 @@ package com.celzero.bravedns.adapter import Logger import Logger.LOG_TAG_UI import android.content.Context -import android.content.res.ColorStateList import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -33,34 +32,29 @@ import com.celzero.bravedns.data.AppConnection import com.celzero.bravedns.databinding.ListItemAppIpDetailsBinding import com.celzero.bravedns.service.IpRulesManager import com.celzero.bravedns.ui.bottomsheet.AppIpRulesBottomSheet -import com.celzero.bravedns.util.UIUtils.fetchColor +import com.celzero.bravedns.util.UIUtils +import com.celzero.bravedns.util.Utilities import com.celzero.bravedns.util.Utilities.removeBeginningTrailingCommas +import kotlin.math.log2 class AppWiseIpsAdapter(val context: Context, val lifecycleOwner: LifecycleOwner, val uid: Int) : PagingDataAdapter(DIFF_CALLBACK), AppIpRulesBottomSheet.OnBottomSheetDialogFragmentDismiss { + private var maxValue: Int = 0 + private var minPercentage: Int = 100 + companion object { private val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(old: AppConnection, new: AppConnection) = old == new - override fun areItemsTheSame( - oldConnection: AppConnection, - newConnection: AppConnection - ) = oldConnection == newConnection - - override fun areContentsTheSame( - oldConnection: AppConnection, - newConnection: AppConnection - ) = oldConnection == newConnection + override fun areContentsTheSame(old: AppConnection, new: AppConnection) = old == new } } private lateinit var adapter: AppWiseIpsAdapter - // ui component to update/toggle the buttons - data class ToggleBtnUi(val txtColor: Int, val bgColor: Int) - override fun onCreateViewHolder( parent: ViewGroup, viewType: Int @@ -80,6 +74,24 @@ class AppWiseIpsAdapter(val context: Context, val lifecycleOwner: LifecycleOwner holder.update(appConnection) } + private fun calculatePercentage(c: Double): Int { + val value = (log2(c) * 100).toInt() + // maxValue will be based on the count returned by db query (order by count desc) + if (value > maxValue) { + maxValue = value + } + return if (maxValue == 0) { + 0 + } else { + val percentage = (value * 100 / maxValue) + // minPercentage is used to show the progress bar when the percentage is 0 + if (percentage < minPercentage && percentage != 0) { + minPercentage = percentage + } + percentage + } + } + inner class ConnectionDetailsViewHolder(private val b: ListItemAppIpDetailsBinding) : RecyclerView.ViewHolder(b.root) { fun update(conn: AppConnection) { @@ -87,16 +99,16 @@ class AppWiseIpsAdapter(val context: Context, val lifecycleOwner: LifecycleOwner setupClickListeners(conn) } - private fun setupClickListeners(appConn: AppConnection) { + private fun setupClickListeners(conn: AppConnection) { b.acdContainer.setOnClickListener { // open bottom sheet to apply domain/ip rules - openBottomSheet(appConn) + openBottomSheet(conn) } } - private fun openBottomSheet(appConn: AppConnection) { + private fun openBottomSheet(conn: AppConnection) { if (context !is AppCompatActivity) { - Logger.w(LOG_TAG_UI, "Error opening the app conn bottom sheet") + Logger.w(LOG_TAG_UI, "err opening the app conn bottom sheet") return } @@ -107,26 +119,27 @@ class AppWiseIpsAdapter(val context: Context, val lifecycleOwner: LifecycleOwner // so sending the data using Bundles val bundle = Bundle() bundle.putInt(AppIpRulesBottomSheet.UID, uid) - bundle.putString(AppIpRulesBottomSheet.IP_ADDRESS, appConn.ipAddress) + bundle.putString(AppIpRulesBottomSheet.IP_ADDRESS, conn.ipAddress) bundle.putString( AppIpRulesBottomSheet.DOMAINS, - beautifyDomainString(appConn.appOrDnsName ?: "") + beautifyDomainString(conn.appOrDnsName ?: "") ) bottomSheetFragment.arguments = bundle bottomSheetFragment.dismissListener(adapter, absoluteAdapterPosition) bottomSheetFragment.show(context.supportFragmentManager, bottomSheetFragment.tag) } - private fun displayTransactionDetails(appConnection: AppConnection) { - b.acdCount.text = appConnection.count.toString() - b.acdIpAddress.text = appConnection.ipAddress - if (!appConnection.appOrDnsName.isNullOrEmpty()) { + private fun displayTransactionDetails(conn: AppConnection) { + b.acdCount.text = conn.count.toString() + b.acdIpAddress.text = conn.ipAddress + b.acdFlag.text = conn.flag + if (!conn.appOrDnsName.isNullOrEmpty()) { b.acdDomainName.visibility = View.VISIBLE - b.acdDomainName.text = beautifyDomainString(appConnection.appOrDnsName) + b.acdDomainName.text = beautifyDomainString(conn.appOrDnsName) } else { b.acdDomainName.visibility = View.GONE } - updateStatusUi(appConnection.uid, appConnection.ipAddress) + updateStatusUi(conn) } private fun beautifyDomainString(d: String): String { @@ -135,56 +148,41 @@ class AppWiseIpsAdapter(val context: Context, val lifecycleOwner: LifecycleOwner return removeBeginningTrailingCommas(d).replace(",,", ",").replace(",", ", ") } - private fun updateStatusUi(uid: Int, ipAddress: String) { - val status = IpRulesManager.getMostSpecificRuleMatch(uid, ipAddress) + private fun updateStatusUi(conn: AppConnection) { + val status = IpRulesManager.getMostSpecificRuleMatch(conn.uid, conn.ipAddress) when (status) { IpRulesManager.IpRuleStatus.NONE -> { - b.acdFlag.text = context.getString(R.string.ci_no_rule_initial) - } - IpRulesManager.IpRuleStatus.BLOCK -> { - b.acdFlag.text = context.getString(R.string.ci_blocked_initial) - } - IpRulesManager.IpRuleStatus.BYPASS_UNIVERSAL -> { - b.acdFlag.text = context.getString(R.string.ci_bypass_universal_initial) - } - IpRulesManager.IpRuleStatus.TRUST -> { - b.acdFlag.text = context.getString(R.string.ci_trust_initial) - } - } - - // returns the text and background color for the button - val t = getToggleBtnUiParams(status) - b.acdFlag.setTextColor(t.txtColor) - b.acdFlag.backgroundTintList = ColorStateList.valueOf(t.bgColor) - } - - private fun getToggleBtnUiParams(id: IpRulesManager.IpRuleStatus): ToggleBtnUi { - return when (id) { - IpRulesManager.IpRuleStatus.NONE -> { - ToggleBtnUi( - fetchColor(context, R.attr.chipTextNeutral), - fetchColor(context, R.attr.chipBgColorNeutral) + b.progress.setIndicatorColor( + UIUtils.fetchToggleBtnColors(context, R.color.chipTextNeutral) ) } IpRulesManager.IpRuleStatus.BLOCK -> { - ToggleBtnUi( - fetchColor(context, R.attr.chipTextNegative), - fetchColor(context, R.attr.chipBgColorNegative) + b.progress.setIndicatorColor( + UIUtils.fetchToggleBtnColors(context, R.color.accentBad) ) } IpRulesManager.IpRuleStatus.BYPASS_UNIVERSAL -> { - ToggleBtnUi( - fetchColor(context, R.attr.chipTextPositive), - fetchColor(context, R.attr.chipBgColorPositive) + b.progress.setIndicatorColor( + UIUtils.fetchToggleBtnColors(context, R.color.accentGood) ) } IpRulesManager.IpRuleStatus.TRUST -> { - ToggleBtnUi( - fetchColor(context, R.attr.chipTextPositive), - fetchColor(context, R.attr.chipBgColorPositive) + b.progress.setIndicatorColor( + UIUtils.fetchToggleBtnColors(context, R.color.accentGood) ) } } + + var p = calculatePercentage(conn.count.toDouble()) + if (p == 0) { + p = minPercentage / 2 + } + + if (Utilities.isAtleastN()) { + b.progress.setProgress(p, true) + } else { + b.progress.progress = p + } } } diff --git a/app/src/full/java/com/celzero/bravedns/adapter/WgPeersAdapter.kt b/app/src/full/java/com/celzero/bravedns/adapter/WgPeersAdapter.kt index 838702dd..7c9a2919 100644 --- a/app/src/full/java/com/celzero/bravedns/adapter/WgPeersAdapter.kt +++ b/app/src/full/java/com/celzero/bravedns/adapter/WgPeersAdapter.kt @@ -28,6 +28,7 @@ import com.celzero.bravedns.databinding.ListItemWgPeersBinding import com.celzero.bravedns.service.WireguardManager import com.celzero.bravedns.service.WireguardManager.WARP_ID import com.celzero.bravedns.ui.dialog.WgAddPeerDialog +import com.celzero.bravedns.util.UIUtils import com.celzero.bravedns.wireguard.Peer import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.Dispatchers @@ -76,7 +77,11 @@ class WgPeersAdapter( b.allowedIpsLabel.visibility = View.GONE } if (wgPeer.persistentKeepalive.isPresent) { - b.persistentKeepaliveText.text = wgPeer.persistentKeepalive.get().toString() + b.persistentKeepaliveText.text = + UIUtils.getDurationInHumanReadableFormat( + context, + wgPeer.persistentKeepalive.get() + ) } else { b.persistentKeepaliveText.visibility = View.GONE b.persistentKeepaliveLabel.visibility = View.GONE diff --git a/app/src/full/java/com/celzero/bravedns/ui/HomeScreenActivity.kt b/app/src/full/java/com/celzero/bravedns/ui/HomeScreenActivity.kt index c2b2ab4e..81649ecc 100644 --- a/app/src/full/java/com/celzero/bravedns/ui/HomeScreenActivity.kt +++ b/app/src/full/java/com/celzero/bravedns/ui/HomeScreenActivity.kt @@ -54,6 +54,7 @@ import com.celzero.bravedns.backup.BackupHelper.Companion.BACKUP_FILE_EXTN import com.celzero.bravedns.backup.BackupHelper.Companion.INTENT_RESTART_APP import com.celzero.bravedns.backup.BackupHelper.Companion.INTENT_SCHEME import com.celzero.bravedns.backup.RestoreAgent +import com.celzero.bravedns.data.AppConfig import com.celzero.bravedns.database.RefreshDatabase import com.celzero.bravedns.databinding.ActivityHomeScreenBinding import com.celzero.bravedns.service.AppUpdater @@ -75,18 +76,19 @@ import com.celzero.bravedns.util.Utilities.showToastUiCentered import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar +import java.util.Calendar +import java.util.concurrent.Executor +import java.util.concurrent.TimeUnit import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.koin.android.ext.android.get import org.koin.android.ext.android.inject -import java.util.Calendar -import java.util.concurrent.Executor -import java.util.concurrent.TimeUnit class HomeScreenActivity : AppCompatActivity(R.layout.activity_home_screen) { private val b by viewBinding(ActivityHomeScreenBinding::bind) private val persistentState by inject() + private val appConfig by inject() private val appUpdateManager by inject() private val rdb by inject() @@ -120,6 +122,7 @@ class HomeScreenActivity : AppCompatActivity(R.layout.activity_home_screen) { // do not launch on board activity when app is running on TV if (persistentState.firstTimeLaunch && !isAppRunningOnTv()) { launchOnboardActivity() + rdnsRemote() return } updateNewVersion() @@ -392,6 +395,18 @@ class HomeScreenActivity : AppCompatActivity(R.layout.activity_home_screen) { persistentState.biometricAuthTime = SystemClock.elapsedRealtime() } + private fun rdnsRemote() { + // enforce the dns to sky for play store build, and max for website and f-droid build + // on first time launch + io { + if (isPlayStoreFlavour()) { + appConfig.switchRethinkDnsToSky() + } else { + appConfig.switchRethinkDnsToMax() + } + } + } + // fixme: find a cleaner way to implement this, move this to some other place private fun moveRemoteBlocklistFileFromAsset() { io { diff --git a/app/src/full/java/com/celzero/bravedns/ui/dialog/WgAddPeerDialog.kt b/app/src/full/java/com/celzero/bravedns/ui/dialog/WgAddPeerDialog.kt index da078524..3f91c291 100644 --- a/app/src/full/java/com/celzero/bravedns/ui/dialog/WgAddPeerDialog.kt +++ b/app/src/full/java/com/celzero/bravedns/ui/dialog/WgAddPeerDialog.kt @@ -19,13 +19,18 @@ import Logger import android.app.Activity import android.app.Dialog import android.os.Bundle +import android.view.View import android.view.Window import android.view.WindowManager +import android.view.inputmethod.EditorInfo +import android.widget.TextView.OnEditorActionListener import android.widget.Toast +import androidx.core.widget.doOnTextChanged import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import com.celzero.bravedns.databinding.DialogWgAddPeerBinding import com.celzero.bravedns.service.WireguardManager +import com.celzero.bravedns.util.UIUtils.getDurationInHumanReadableFormat import com.celzero.bravedns.util.Utilities import com.celzero.bravedns.wireguard.Peer import com.celzero.bravedns.wireguard.util.ErrorMessages @@ -71,9 +76,12 @@ class WgAddPeerDialog( b.peerEndpoint.setText(wgPeer.getEndpoint().get().toString()) } if (wgPeer.persistentKeepalive.isPresent) { - b.peerPersistentKeepAlive.setText(wgPeer.persistentKeepalive.get().toString()) + val kas = wgPeer.persistentKeepalive.get() + b.keepAliveHint.visibility = View.VISIBLE + b.peerPersistentKeepAlive.setText(kas.toString()) + b.keepAliveHint.text = getDurationInHumanReadableFormat(activity, kas) } else { - // no-op + b.keepAliveHint.visibility = View.GONE } } } @@ -81,6 +89,20 @@ class WgAddPeerDialog( private fun setupClickListener() { b.customDialogDismissButton.setOnClickListener { this.dismiss() } + b.peerPersistentKeepAlive.doOnTextChanged { text, _, _, _ -> + if (text.toString().isNotEmpty()) { + try { + val kas = text.toString().toInt() + b.keepAliveHint.visibility = View.VISIBLE + b.keepAliveHint.text = getDurationInHumanReadableFormat(activity, kas) + } catch (e: NumberFormatException) { + b.keepAliveHint.visibility = View.GONE + } + } else { + b.keepAliveHint.visibility = View.GONE + } + } + b.customDialogOkButton.setOnClickListener { val peerPublicKey = b.peerPublicKey.text.toString() val presharedKey = b.peerPresharedKey.text.toString() diff --git a/app/src/full/java/com/celzero/bravedns/ui/fragment/HomeScreenFragment.kt b/app/src/full/java/com/celzero/bravedns/ui/fragment/HomeScreenFragment.kt index 9b468135..974d99fe 100644 --- a/app/src/full/java/com/celzero/bravedns/ui/fragment/HomeScreenFragment.kt +++ b/app/src/full/java/com/celzero/bravedns/ui/fragment/HomeScreenFragment.kt @@ -20,6 +20,7 @@ import Logger.LOG_TAG_UI import Logger.LOG_TAG_VPN import android.Manifest import android.app.Activity +import android.app.ActivityManager import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent @@ -75,20 +76,22 @@ import com.celzero.bravedns.util.UIUtils.updateHtmlEncodedText import com.celzero.bravedns.util.Utilities.delay import com.celzero.bravedns.util.Utilities.getPrivateDnsMode import com.celzero.bravedns.util.Utilities.isAtleastN +import com.celzero.bravedns.util.Utilities.isAtleastP +import com.celzero.bravedns.util.Utilities.isAtleastU import com.celzero.bravedns.util.Utilities.isOtherVpnHasAlwaysOn import com.celzero.bravedns.util.Utilities.isPrivateDnsActive import com.celzero.bravedns.util.Utilities.showToastUiCentered import com.facebook.shimmer.Shimmer import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar +import java.util.* +import java.util.concurrent.TimeUnit import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.koin.android.ext.android.inject -import java.util.* -import java.util.concurrent.TimeUnit class HomeScreenFragment : Fragment(R.layout.fragment_home_screen) { private val b by viewBinding(FragmentHomeScreenBinding::bind) @@ -745,12 +748,15 @@ class HomeScreenFragment : Fragment(R.layout.fragment_home_screen) { } private fun batteryOptimizationActive(context: Context): Boolean { - val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager - Logger.d( - LOG_TAG_UI, - "ignore battery optimization: ${powerManager.isIgnoringBatteryOptimizations(context.packageName)}" - ) - return !powerManager.isIgnoringBatteryOptimizations(context.packageName) + val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager + val exemptFromBatteryOptimization = pm.isIgnoringBatteryOptimizations(context.packageName) + Logger.d(LOG_TAG_UI, "ignore battery optimization: $exemptFromBatteryOptimization") + + return if (isAtleastU()) { + !pm.isExemptFromLowPowerStandby || !exemptFromBatteryOptimization + } else { + !exemptFromBatteryOptimization + } } private fun showBatteryOptimizationDialog() { @@ -794,14 +800,18 @@ class HomeScreenFragment : Fragment(R.layout.fragment_home_screen) { private fun isRestrictBackgroundActive(context: Context): Boolean { if (!isAtleastN()) return false - val connectivityManager = - context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager - Logger.d( - LOG_TAG_UI, - "restrict background status: ${connectivityManager.restrictBackgroundStatus}" - ) - return connectivityManager.restrictBackgroundStatus == - ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED + val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val isBackgroundRestricted = cm.restrictBackgroundStatus + Logger.d(LOG_TAG_UI, "restrict background status: $isBackgroundRestricted") + + return if (isAtleastP()) { + val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + Logger.d(LOG_TAG_UI, "above P, background restricted: ${am.isBackgroundRestricted}") + am.isBackgroundRestricted || + isBackgroundRestricted == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED + } else { + isBackgroundRestricted == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED + } } private fun showRestrictBgActiveDialog() { diff --git a/app/src/full/java/com/celzero/bravedns/util/UIUtils.kt b/app/src/full/java/com/celzero/bravedns/util/UIUtils.kt index a4a412a4..956a9169 100644 --- a/app/src/full/java/com/celzero/bravedns/util/UIUtils.kt +++ b/app/src/full/java/com/celzero/bravedns/util/UIUtils.kt @@ -278,6 +278,18 @@ object UIUtils { R.attr.accentGood } else if (attr == R.color.accentBad) { R.attr.accentBad + } else if (attr == R.color.chipBgNeutral) { + R.attr.chipBgColorNeutral + } else if (attr == R.color.chipBgNegative) { + R.attr.chipBgColorNegative + } else if (attr == R.color.chipBgPositive) { + R.attr.chipBgColorPositive + } else if (attr == R.color.chipTextNeutral) { + R.attr.chipTextNeutral + } else if (attr == R.color.chipTextNegative) { + R.attr.chipTextNegative + } else if (attr == R.color.chipTextPositive) { + R.attr.chipTextPositive } else { R.attr.chipBgColorPositive } diff --git a/app/src/full/res/layout/list_item_app_domain_details.xml b/app/src/full/res/layout/list_item_app_domain_details.xml index 3c8a7dc2..4d8c62df 100644 --- a/app/src/full/res/layout/list_item_app_domain_details.xml +++ b/app/src/full/res/layout/list_item_app_domain_details.xml @@ -1,5 +1,6 @@ - - + android:textAppearance="@style/TextAppearance.AppCompat.Headline" + android:textSize="26sp" /> + + android:orientation="vertical"> + + + + + \ No newline at end of file diff --git a/app/src/full/res/layout/list_item_app_ip_details.xml b/app/src/full/res/layout/list_item_app_ip_details.xml index 16503cbe..3ca987a3 100644 --- a/app/src/full/res/layout/list_item_app_ip_details.xml +++ b/app/src/full/res/layout/list_item_app_ip_details.xml @@ -1,5 +1,6 @@ - - + android:textAppearance="@style/TextAppearance.AppCompat.Headline" + android:textSize="26sp" /> + + android:orientation="vertical"> + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index af40a67c..cfe5ba31 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="40" + android:versionName="v055i"> diff --git a/app/src/main/java/com/celzero/bravedns/data/AppConfig.kt b/app/src/main/java/com/celzero/bravedns/data/AppConfig.kt index b3daa21f..7c5bb79e 100644 --- a/app/src/main/java/com/celzero/bravedns/data/AppConfig.kt +++ b/app/src/main/java/com/celzero/bravedns/data/AppConfig.kt @@ -77,7 +77,7 @@ internal constructor( private const val ORBOT_DNS = "Orbot" - const val FALLBACK_DNS = "8.8.4.4" + const val FALLBACK_DNS = "8.8.4.4, 2001:4860:4860::8844" } init { diff --git a/app/src/main/java/com/celzero/bravedns/database/ConnectionTrackerDAO.kt b/app/src/main/java/com/celzero/bravedns/database/ConnectionTrackerDAO.kt index 055f45a7..858dee70 100644 --- a/app/src/main/java/com/celzero/bravedns/database/ConnectionTrackerDAO.kt +++ b/app/src/main/java/com/celzero/bravedns/database/ConnectionTrackerDAO.kt @@ -89,22 +89,22 @@ interface ConnectionTrackerDAO { fun getBlockedConnections(query: String): PagingSource @Query( - "SELECT uid, ipAddress, port, COUNT(ipAddress) as count, '' as flag, 0 as blocked, GROUP_CONCAT(DISTINCT dnsQuery) as appOrDnsName FROM ConnectionTracker WHERE uid = :uid GROUP BY ipAddress, uid, port ORDER BY count DESC" + "SELECT uid, ipAddress, port, COUNT(ipAddress) as count, flag as flag, 0 as blocked, GROUP_CONCAT(DISTINCT dnsQuery) as appOrDnsName FROM ConnectionTracker WHERE uid = :uid GROUP BY ipAddress, uid, port ORDER BY count DESC" ) fun getAppIpLogs(uid: Int): PagingSource @Query( - "SELECT uid, ipAddress, port, COUNT(ipAddress) as count, '' as flag, 0 as blocked, GROUP_CONCAT(DISTINCT dnsQuery) as appOrDnsName FROM ConnectionTracker WHERE uid = :uid and ipAddress like :query GROUP BY ipAddress, uid, port ORDER BY count DESC" + "SELECT uid, ipAddress, port, COUNT(ipAddress) as count, flag as flag, 0 as blocked, GROUP_CONCAT(DISTINCT dnsQuery) as appOrDnsName FROM ConnectionTracker WHERE uid = :uid and ipAddress like :query GROUP BY ipAddress, uid, port ORDER BY count DESC" ) fun getAppIpLogsFiltered(uid: Int, query: String): PagingSource @Query( - "SELECT uid, GROUP_CONCAT(DISTINCT ipAddress) as ipAddress, port, COUNT(dnsQuery) as count, '' as flag, 0 as blocked, dnsQuery as appOrDnsName FROM ConnectionTracker WHERE uid = :uid and dnsQuery != '' GROUP BY dnsQuery ORDER BY count DESC" + "SELECT uid, GROUP_CONCAT(DISTINCT ipAddress) as ipAddress, port, COUNT(dnsQuery) as count, flag as flag, 0 as blocked, dnsQuery as appOrDnsName FROM ConnectionTracker WHERE uid = :uid and dnsQuery != '' GROUP BY dnsQuery ORDER BY count DESC" ) fun getAppDomainLogs(uid: Int): PagingSource @Query( - "SELECT uid, GROUP_CONCAT(DISTINCT ipAddress) as ipAddress, port, COUNT(dnsQuery) as count, '' as flag, 0 as blocked, dnsQuery as appOrDnsName FROM ConnectionTracker WHERE uid = :uid and dnsQuery != '' and dnsQuery like :query GROUP BY dnsQuery ORDER BY count DESC" + "SELECT uid, GROUP_CONCAT(DISTINCT ipAddress) as ipAddress, port, COUNT(dnsQuery) as count, flag as flag, 0 as blocked, dnsQuery as appOrDnsName FROM ConnectionTracker WHERE uid = :uid and dnsQuery != '' and dnsQuery like :query GROUP BY dnsQuery ORDER BY count DESC" ) fun getAppDomainLogsFiltered(uid: Int, query: String): PagingSource diff --git a/app/src/main/java/com/celzero/bravedns/net/go/GoVpnAdapter.kt b/app/src/main/java/com/celzero/bravedns/net/go/GoVpnAdapter.kt index ece6260d..861f0632 100644 --- a/app/src/main/java/com/celzero/bravedns/net/go/GoVpnAdapter.kt +++ b/app/src/main/java/com/celzero/bravedns/net/go/GoVpnAdapter.kt @@ -894,7 +894,7 @@ class GoVpnAdapter : KoinComponent { private fun newDefaultTransport(url: String): intra.DefaultDNS { val defaultDns = FALLBACK_DNS try { - // when the url is empty, set the default transport to 8.8.4.4:53 + // when the url is empty, set the default transport to 8.8.4.4, 2001:4860:4860::8844 if (url.isEmpty()) { Logger.i(LOG_TAG_VPN, "set default transport to $defaultDns, as url is empty") return Intra.newDefaultDNS(Backend.DNS53, defaultDns, "") @@ -921,7 +921,7 @@ class GoVpnAdapter : KoinComponent { Logger.i(LOG_TAG_VPN, "Tunnel not connected, skip new default transport") return } - // when the url is empty, set the default transport to DEFAULT_DNS_IP + // when the url is empty, set the default transport to FALLBACK_DNS // default transport is always sent to Ipn.Exit in the go code and so dns // request sent to the default transport will not be looped back into the tunnel if (url.isNullOrEmpty()) { diff --git a/app/src/main/res/layout/activity_app_wise_domain_logs.xml b/app/src/main/res/layout/activity_app_wise_domain_logs.xml index 83f2b961..ff61a0f8 100644 --- a/app/src/main/res/layout/activity_app_wise_domain_logs.xml +++ b/app/src/main/res/layout/activity_app_wise_domain_logs.xml @@ -12,12 +12,13 @@ android:layout_height="wrap_content" android:layout_marginStart="10dp" android:layout_marginEnd="10dp" + android:layout_marginTop="10dp" android:padding="5dp"> diff --git a/app/src/main/res/layout/activity_app_wise_ip_logs.xml b/app/src/main/res/layout/activity_app_wise_ip_logs.xml index 5368aeaf..bd909033 100644 --- a/app/src/main/res/layout/activity_app_wise_ip_logs.xml +++ b/app/src/main/res/layout/activity_app_wise_ip_logs.xml @@ -12,12 +12,13 @@ android:layout_height="wrap_content" android:layout_marginStart="10dp" android:layout_marginEnd="10dp" + android:layout_marginTop="10dp" android:padding="5dp"> diff --git a/app/src/main/res/layout/dialog_wg_add_peer.xml b/app/src/main/res/layout/dialog_wg_add_peer.xml index e1e0d145..3a3868cc 100644 --- a/app/src/main/res/layout/dialog_wg_add_peer.xml +++ b/app/src/main/res/layout/dialog_wg_add_peer.xml @@ -116,6 +116,18 @@ android:inputType="number" /> + + Choose mode - JA Donenfeld 2.0

+ JA Donenfeld 4.0

1. Show upload, download stats for WireGuard.
2. Auto recover dropped WireGuard connections.
3. Implement Android\'s seamless handover on network changes.
- 4. Support for multiple DNSCrypt relays.
- 5. Bug fix: Close packet capture file when appropriate.
- 6. Other bug fixed and improvements.

+ 4. New UI for per-app Network and DNS logs.
+ 5. Support for multiple DNSCrypt relays.
+ 6. Improvement: Show WireGuard Peer handshake time periods.
+ 7. Bug fix: Prevent multi package apps auto-deleting from WireGuard configs.
+ 8. Bug fix: Inaccessible On-device blocklists Configure UI.
+ 9. Bug fix: Close packet capture file when appropriate.
+ 10. Bug fix: Fix crash when stopping WireGuard.
+ 11. Other bug fixed and improvements.

Help translate this app]]>
@@ -1463,7 +1468,7 @@ Routing all apps Lockdown - Selected apps will only be routed through this WireGuard VPN, regardless of whether the VPN is failing or connected. + Selected apps will only be routed through this WireGuard VPN, regardless of whether the VPN is active or disabled. All connections from all apps, including DNS, will be routed to a single, active WireGuard VPN. Other active WireGuard VPNs, if any, will be stopped. diff --git a/gradle.properties b/gradle.properties index e654a8a8..3b311b1f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,5 +24,5 @@ android.nonTransitiveRClass=true # Enable configuration cache org.gradle.unsafe.configuration-cache=true android.nonFinalResIds=true -# Version code for this module (39 for v055h) -VERSION_CODE=39 +# Version code for this module (40 for v055i) +VERSION_CODE=40