diff --git a/CMakeLists.txt b/CMakeLists.txt
index 18c32f30..5b2885f4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
-project(${PROJECT} VERSION 4.4.2.1
+project(${PROJECT} VERSION 4.4.2.2
DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/"
)
@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
-set(APP_ANDROID_VERSION_CODE 49)
+set(APP_ANDROID_VERSION_CODE 50)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
diff --git a/client/android/res/values-ru/strings.xml b/client/android/res/values-ru/strings.xml
index f0070c0e..53cb9c45 100644
--- a/client/android/res/values-ru/strings.xml
+++ b/client/android/res/values-ru/strings.xml
@@ -2,4 +2,11 @@
Подключение
Отключение
+ Отмена
+ ОК
+ VPN-подключение разрешено
+ VPN-подключение запрещено
+ Ошибка настройки VPN
+ Чтобы подключиться к AmneziaVPN необходимо:\n\n- Разрешить приложению подключаться к сети VPN\n- Отключить функцию \"Постоянная VPN\" для всех остальных VPN-приложений в системных настройках VPN
+ Открыть настройки VPN
\ No newline at end of file
diff --git a/client/android/res/values/strings.xml b/client/android/res/values/strings.xml
index 3fdd9844..9172d14b 100644
--- a/client/android/res/values/strings.xml
+++ b/client/android/res/values/strings.xml
@@ -2,4 +2,11 @@
Connecting
Disconnecting
+ Cancel
+ OK
+ VPN permission granted
+ VPN permission denied
+ VPN setup error
+ To connect to AmneziaVPN, please do the following:\n\n- Allow the app to set up a VPN connection\n- Disable Always-on VPN for any other VPN app in the VPN system settings
+ Open VPN settings
\ No newline at end of file
diff --git a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt
index ff25ab05..ef31a7d2 100644
--- a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt
+++ b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt
@@ -1,5 +1,6 @@
package org.amnezia.vpn
+import android.app.AlertDialog
import android.content.ComponentName
import android.content.Intent
import android.content.Intent.EXTRA_MIME_TYPES
@@ -14,6 +15,7 @@ import android.os.IBinder
import android.os.Looper
import android.os.Message
import android.os.Messenger
+import android.provider.Settings
import android.view.WindowManager.LayoutParams
import android.webkit.MimeTypeMap
import android.widget.Toast
@@ -216,13 +218,13 @@ class AmneziaActivity : QtActivity() {
when (resultCode) {
RESULT_OK -> {
Log.d(TAG, "Vpn permission granted")
- Toast.makeText(this, "Vpn permission granted", Toast.LENGTH_LONG).show()
+ Toast.makeText(this, resources.getText(R.string.vpnGranted), Toast.LENGTH_LONG).show()
checkVpnPermissionCallbacks?.run { onSuccess() }
}
else -> {
Log.w(TAG, "Vpn permission denied, resultCode: $resultCode")
- Toast.makeText(this, "Vpn permission denied", Toast.LENGTH_LONG).show()
+ showOnVpnPermissionRejectDialog()
checkVpnPermissionCallbacks?.run { onFail() }
}
}
@@ -280,6 +282,17 @@ class AmneziaActivity : QtActivity() {
onSuccess()
}
+ private fun showOnVpnPermissionRejectDialog() {
+ AlertDialog.Builder(this)
+ .setTitle(R.string.vpnSetupFailed)
+ .setMessage(R.string.vpnSetupFailedMessage)
+ .setNegativeButton(R.string.ok) { _, _ -> }
+ .setPositiveButton(R.string.openVpnSettings) { _, _ ->
+ startActivity(Intent(Settings.ACTION_VPN_SETTINGS))
+ }
+ .show()
+ }
+
@MainThread
private fun startVpn(vpnConfig: String) {
if (isServiceConnected) {
diff --git a/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt b/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt
index 094383e8..d0a1e8e8 100644
--- a/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt
+++ b/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt
@@ -215,11 +215,9 @@ class AmneziaVpnService : VpnService() {
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- val isAlwaysOnCompat =
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) isAlwaysOn
- else intent?.component?.packageName != packageName
+ val isAlwaysOn = intent != null && intent.action == SERVICE_INTERFACE
- if (isAlwaysOnCompat) {
+ if (isAlwaysOn) {
Log.d(TAG, "Start service via Always-on")
connect()
} else if (intent?.getBooleanExtra(AFTER_PERMISSION_CHECK, false) == true) {
diff --git a/client/android/src/org/amnezia/vpn/VpnRequestActivity.kt b/client/android/src/org/amnezia/vpn/VpnRequestActivity.kt
index c5abbc39..74aeb578 100644
--- a/client/android/src/org/amnezia/vpn/VpnRequestActivity.kt
+++ b/client/android/src/org/amnezia/vpn/VpnRequestActivity.kt
@@ -1,12 +1,16 @@
package org.amnezia.vpn
+import android.app.AlertDialog
import android.app.KeyguardManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.res.Configuration.UI_MODE_NIGHT_MASK
+import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.net.VpnService
import android.os.Bundle
+import android.provider.Settings
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResult
@@ -52,19 +56,43 @@ class VpnRequestActivity : ComponentActivity() {
}
private fun checkRequestResult(result: ActivityResult) {
- when (result.resultCode) {
- RESULT_OK -> onPermissionGranted()
- else -> Toast.makeText(this, "Vpn permission denied", Toast.LENGTH_LONG).show()
+ when (val resultCode = result.resultCode) {
+ RESULT_OK -> {
+ onPermissionGranted()
+ finish()
+ }
+
+ else -> {
+ Log.w(TAG, "Vpn permission denied, resultCode: $resultCode")
+ showOnVpnPermissionRejectDialog()
+ }
}
- finish()
}
private fun onPermissionGranted() {
- Toast.makeText(this, "Vpn permission granted", Toast.LENGTH_LONG).show()
+ Toast.makeText(this, resources.getString(R.string.vpnGranted), Toast.LENGTH_LONG).show()
Intent(applicationContext, AmneziaVpnService::class.java).apply {
putExtra(AFTER_PERMISSION_CHECK, true)
}.also {
ContextCompat.startForegroundService(this, it)
}
}
+
+ private fun showOnVpnPermissionRejectDialog() {
+ AlertDialog.Builder(this, getDialogTheme())
+ .setTitle(R.string.vpnSetupFailed)
+ .setMessage(R.string.vpnSetupFailedMessage)
+ .setNegativeButton(R.string.ok) { _, _ -> }
+ .setPositiveButton(R.string.openVpnSettings) { _, _ ->
+ startActivity(Intent(Settings.ACTION_VPN_SETTINGS))
+ }
+ .setOnDismissListener { finish() }
+ .show()
+ }
+
+ private fun getDialogTheme(): Int =
+ if (resources.configuration.uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES)
+ android.R.style.Theme_DeviceDefault_Dialog_Alert
+ else
+ android.R.style.Theme_DeviceDefault_Light_Dialog_Alert
}
diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
index 95ea9aca..9b54cfb5 100644
--- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
+++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
@@ -157,7 +157,7 @@ open class Wireguard : Protocol() {
if (tunFd == null) {
throw VpnStartException("Create VPN interface: permission not granted or revoked")
}
- Log.v(TAG, "Wg-go backend ${GoBackend.awgVersion()}")
+ Log.i(TAG, "awg-go backend ${GoBackend.awgVersion()}")
tunnelHandle = GoBackend.awgTurnOn(ifName, tunFd.detachFd(), config.toWgUserspaceString())
}
diff --git a/client/cmake/android.cmake b/client/cmake/android.cmake
index fe4a607c..20fc617d 100644
--- a/client/cmake/android.cmake
+++ b/client/cmake/android.cmake
@@ -42,9 +42,7 @@ set(SOURCES ${SOURCES}
foreach(abi IN ITEMS ${QT_ANDROID_ABIS})
set_property(TARGET ${PROJECT} PROPERTY QT_ANDROID_EXTRA_LIBS
- ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/amneziawg/android/${abi}/libwg.so
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/amneziawg/android/${abi}/libwg-go.so
- ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/amneziawg/android/${abi}/libwg-quick.so
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/android/${abi}/libck-ovpn-plugin.so
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/android/${abi}/libovpn3.so
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/android/${abi}/libovpnutil.so