diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt index d505c44179b2..cd3e94bc6539 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt @@ -160,6 +160,8 @@ class ConnectViewModel( if (hasVpnPermission) { connectionProxy.connect() } else { + // Either the user denied the permission or another always-on-vpn is active (if + // Android 11+ and run from Android Studio) _uiSideEffect.send(UiSideEffect.ConnectError.PermissionDenied) } } diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/ContextExtensions.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/ContextExtensions.kt index 992ae9404d13..882279c99911 100644 --- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/ContextExtensions.kt +++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/ContextExtensions.kt @@ -3,11 +3,8 @@ package net.mullvad.mullvadvpn.lib.common.util import android.content.Context import android.content.Intent import android.net.Uri -import android.provider.Settings import net.mullvad.mullvadvpn.lib.model.WebsiteAuthToken -private const val ALWAYS_ON_VPN_APP = "always_on_vpn_app" - fun createAccountUri(accountUri: String, websiteAuthToken: WebsiteAuthToken?): Uri { val urlString = buildString { append(accountUri) @@ -19,16 +16,6 @@ fun createAccountUri(accountUri: String, websiteAuthToken: WebsiteAuthToken?): U return Uri.parse(urlString) } -// NOTE: This function will return the current Always-on VPN package's name. In case of either -// Always-on VPN being disabled or not being able to read the state, NULL will be returned. -fun Context.resolveAlwaysOnVpnPackageName(): String? { - return try { - Settings.Secure.getString(contentResolver, ALWAYS_ON_VPN_APP) - } catch (ex: SecurityException) { - null - } -} - fun Context.openVpnSettings() { val intent = Intent("android.settings.VPN_SETTINGS") startActivity(intent) diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt index 06c862936b65..dfc70609e14a 100644 --- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt +++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt @@ -4,7 +4,10 @@ import android.content.Context import android.content.Intent import android.net.VpnService import android.net.VpnService.prepare +import android.os.Build import android.os.ParcelFileDescriptor +import android.provider.Settings +import androidx.annotation.DeprecatedSinceApi import arrow.core.Either import arrow.core.flatMap import arrow.core.left @@ -22,8 +25,9 @@ import net.mullvad.mullvadvpn.lib.model.Prepared * Invoking VpnService.prepare() can result in 3 out comes: * 1. IllegalStateException - There is a legacy VPN profile marked as always on * 2. Intent - * - A: Can-prepare - Create Vpn profile - * - B: Always-on-VPN - Another Vpn Profile is marked as always on + * - A: Can-prepare - Create Vpn profile or Always-on-VPN is not detected in case of Android 11+ + * - B: Always-on-VPN - Another Vpn Profile is marked as always on (Only available up to Android + * 11 or where testOnly is set, e.g builds from Android Studio) * 3. null - The app has the VPN permission * * In case 1 and 2b, you don't know if you have a VPN profile or not. @@ -44,25 +48,44 @@ fun Context.prepareVpnSafe(): Either = if (intent == null) { Prepared.right() } else { - val alwaysOnVpnApp = getAlwaysOnVpnAppName() - if (alwaysOnVpnApp == null) { - PrepareError.NotPrepared(intent).left() - } else { - PrepareError.OtherAlwaysOnApp(alwaysOnVpnApp).left() + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + val alwaysOnVpnApp = getOtherAlwaysOnVpnAppName() + if (alwaysOnVpnApp != null) { + return@flatMap PrepareError.OtherAlwaysOnApp(alwaysOnVpnApp).left() + } } + return@flatMap PrepareError.NotPrepared(intent).left() } } -fun Context.getAlwaysOnVpnAppName(): String? { - return resolveAlwaysOnVpnPackageName() - ?.let { currentAlwaysOnVpn -> - packageManager.getInstalledPackagesList(0).singleOrNull { - it.packageName == currentAlwaysOnVpn && it.packageName != packageName - } +private const val ALWAYS_ON_VPN_APP = "always_on_vpn_app" + +// NOTE: This function will return the current Always-on VPN package's name. In case of either +// Always-on VPN being disabled or not being able to read the state, null will be returned. +// +// Caveat: For Android 11+ it will always return null unless the app is a test build (e.g running +// from Android Studio). +@DeprecatedSinceApi(Build.VERSION_CODES.S) +fun Context.getOtherAlwaysOnVpnAppName(): String? { + val currentAlwaysOnPackageName = + try { + Settings.Secure.getString(contentResolver, ALWAYS_ON_VPN_APP) + } catch (ex: SecurityException) { + return null } - ?.applicationInfo - ?.loadLabel(packageManager) - ?.toString() + + // If we are the current Always-on VPN app, we return null + return if (currentAlwaysOnPackageName == packageName) { + null + } else { + // Resolve package name to app name + packageManager + .getInstalledPackagesList(0) + .firstOrNull { it.packageName == currentAlwaysOnPackageName } + ?.applicationInfo + ?.loadLabel(packageManager) + ?.toString() + } } /** diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/PrepareError.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/PrepareError.kt index 2fea9a921199..f26a48041730 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/PrepareError.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/PrepareError.kt @@ -8,9 +8,10 @@ sealed interface PrepareError : PrepareResult { // Legacy VPN profile is active as Always-on data object OtherLegacyAlwaysOnVpn : PrepareError - // Another VPN app is active as Always-on + // Another VPN app is active as Always-on (Only works up to Android 11 or debug builds) data class OtherAlwaysOnApp(val appName: String) : PrepareError + // VPN profile can be created or Always-on VPN is active but not detected data class NotPrepared(val prepareIntent: Intent) : PrepareError } diff --git a/android/lib/resource/src/main/res/values-da/strings.xml b/android/lib/resource/src/main/res/values-da/strings.xml index 3a9439c4816b..f8be041d9e70 100644 --- a/android/lib/resource/src/main/res/values-da/strings.xml +++ b/android/lib/resource/src/main/res/values-da/strings.xml @@ -378,7 +378,6 @@ Kuponkode er allerede brugt. Det ser ud til, at du har indtastet et kontonummer i stedet for en rabatkuponkode. Hvis du vil ændre den aktive konto, skal du først logge ud. Indløsning af kuponen lykkedes. - VPN-tilladelse blev nægtet, da tunnelen blev oprettet. Prøv at oprette forbindelse igen. Tryk på Opret forbindelse for at anmode om VPN-tilladelse VPN-tilladelsesfejl Vi vil undersøge dette. diff --git a/android/lib/resource/src/main/res/values-de/strings.xml b/android/lib/resource/src/main/res/values-de/strings.xml index f54ff720b04b..4bd5c18ad7f4 100644 --- a/android/lib/resource/src/main/res/values-de/strings.xml +++ b/android/lib/resource/src/main/res/values-de/strings.xml @@ -378,7 +378,6 @@ Der Gutscheincode wurde bereits verwendet. Anscheinend haben Sie eine Kontonummer statt eines Gutscheincodes eingegeben. Wenn Sie das aktive Konto wechseln möchten, melden Sie sich bitte zuerst ab. Der Gutschein wurde erfolgreich eingelöst. - VPN-Berechtigungen wurden beim Erstellen des Tunnels abgelehnt. Drücken Sie auf „Verbinden“, um die VPN-Berechtigung anzufordern VPN-Berechtigungsfehler Wir werden uns das anschauen. diff --git a/android/lib/resource/src/main/res/values-es/strings.xml b/android/lib/resource/src/main/res/values-es/strings.xml index 9fc3c33aa824..f606f2bdf1ad 100644 --- a/android/lib/resource/src/main/res/values-es/strings.xml +++ b/android/lib/resource/src/main/res/values-es/strings.xml @@ -378,7 +378,6 @@ El código del cupón ya se ha usado. Parece que ha introducido un número de cuenta en lugar de un código de cupón. Si desea cambiar la cuenta activa, cierre primero la sesión. El cupón se canjeó correctamente. - Se denegó el permiso para usar una conexión VPN al crear el túnel. Intente volver a establecer la conexión. Pulse conectar para solicitar el permiso de VPN Error en la autorización de la VPN Revisaremos esto. diff --git a/android/lib/resource/src/main/res/values-fi/strings.xml b/android/lib/resource/src/main/res/values-fi/strings.xml index 1450f1bf86b3..d0a9fb8c536f 100644 --- a/android/lib/resource/src/main/res/values-fi/strings.xml +++ b/android/lib/resource/src/main/res/values-fi/strings.xml @@ -378,7 +378,6 @@ Kuponkikoodi on jo käytetty. Näytät syöttäneen tilin numeron etusetelin koodin sijaan. Jos haluat vaihtaa tiliä, kirjaudu ensin ulos nykyiseltä tililtä. Kupongin lunastus onnistui. - VPN-lupa evättiin tunnelia luotaessa. Yritä muodostaa yhteys uudelleen. Pyydä VPN:n käyttölupa yhteydenluontipainiketta painamalla VPN-lupavirhe Tutkimme asiaa. diff --git a/android/lib/resource/src/main/res/values-fr/strings.xml b/android/lib/resource/src/main/res/values-fr/strings.xml index ad8f9f71be10..7640d861e65c 100644 --- a/android/lib/resource/src/main/res/values-fr/strings.xml +++ b/android/lib/resource/src/main/res/values-fr/strings.xml @@ -378,7 +378,6 @@ Le code du bon a déjà été utilisé. Vous semblez avoir saisi un numéro de compte plutôt qu\'un code de bon. Si vous souhaitez modifier le compte actif, veuillez d\'abord vous déconnecter. Le bon a bien été échangé. - La permission VPN a été refusée lors de la création du tunnel. Veuillez essayer de vous reconnecter. Veuillez appuyer sur connexion pour demander l\'autorisation VPN Erreur de permission VPN Nous allons nous pencher dessus. diff --git a/android/lib/resource/src/main/res/values-it/strings.xml b/android/lib/resource/src/main/res/values-it/strings.xml index 41ab9f331289..aaf91a61cb71 100644 --- a/android/lib/resource/src/main/res/values-it/strings.xml +++ b/android/lib/resource/src/main/res/values-it/strings.xml @@ -378,7 +378,6 @@ Il codice voucher è già stato utilizzato. Sembra che tu abbia inserito un numero di account anziché un codice voucher. Se desideri modificare l\'account attivo, effettua prima la disconnessione. Il voucher è stato riscattato correttamente. - L\'autorizzazione VPN è stata negata durante la creazione del tunnel. Prova a connetterti di nuovo. Premi Connetti per richiedere l\'autorizzazione VPN Errore di autorizzazione VPN Verificheremo. diff --git a/android/lib/resource/src/main/res/values-ja/strings.xml b/android/lib/resource/src/main/res/values-ja/strings.xml index dafc1665f40e..13ae8988c5b7 100644 --- a/android/lib/resource/src/main/res/values-ja/strings.xml +++ b/android/lib/resource/src/main/res/values-ja/strings.xml @@ -378,7 +378,6 @@ バウチャーコードはすでに使用されています。 バウチャーコードではなくアカウント番号を入力したようです。有効なアカウントを変更する場合は、先にログアウトしてください。 バウチャーを正常に使用しました。 - トンネルを作成中にVPNへのアクセスが拒否されました。もう一度接続してみてください。 [接続] を押してVPNへのアクセス許可をリクエストしてください VPN許可エラー この問題を調査いたします。 diff --git a/android/lib/resource/src/main/res/values-ko/strings.xml b/android/lib/resource/src/main/res/values-ko/strings.xml index 84c9f848de14..96382e5f17fa 100644 --- a/android/lib/resource/src/main/res/values-ko/strings.xml +++ b/android/lib/resource/src/main/res/values-ko/strings.xml @@ -378,7 +378,6 @@ 이미 사용된 바우처 코드입니다. 바우처 코드 대신 계정 번호를 입력한 것 같습니다. 활성 계정을 변경하려면 먼저 로그아웃하세요. 바우처가 성공적으로 사용되었습니다. - 터널을 만드는 동안 VPN 사용 권한이 거부되었습니다. 다시 연결해 보세요. VPN 권한을 요청하려면 연결을 누르세요 VPN 권한 오류 조사해보겠습니다. diff --git a/android/lib/resource/src/main/res/values-my/strings.xml b/android/lib/resource/src/main/res/values-my/strings.xml index ac9978bbc315..d4e64f3369f2 100644 --- a/android/lib/resource/src/main/res/values-my/strings.xml +++ b/android/lib/resource/src/main/res/values-my/strings.xml @@ -378,7 +378,6 @@ ဘောက်ချာကုဒ် သုံးထားပြီးသား ဖြစ်ပါသည်။ ဘောက်ချာကုဒ်အစား အကောင့်နံပါတ်တစ်ခုကို ထည့်သွင်းထားပုံရသည်။ အသုံးပြုနေသောအကောင့်ကို ပြောင်းလဲလိုပါက ဦးစွာ အကောင့်မှထွက်ပါ။ ဘောက်ချာကို အောင်မြင်စွာ လဲယူခဲ့ပါသည်။ - Tunnel ဖန်တီးနေစဉ် VPN ခွင့်ပြုချက်ကို ပယ်ချခဲ့ပါသည်။ ထပ်မံချိတ်ဆက်ပေးပါ။ VPN ခွင့်ပြုချက်တောင်းရန် ချိတ်ဆက်ရန်ကို နှိပ်ပေးပါ VPN ခွင့်ပြုချက် ချို့ယွင်းချက် ဤသည်ကို စစ်ဆေးလိုက်ပါမည်။ diff --git a/android/lib/resource/src/main/res/values-nb/strings.xml b/android/lib/resource/src/main/res/values-nb/strings.xml index ed14b6dfcdc4..f3aacf6cfb7a 100644 --- a/android/lib/resource/src/main/res/values-nb/strings.xml +++ b/android/lib/resource/src/main/res/values-nb/strings.xml @@ -378,7 +378,6 @@ Kupongkoden er allerede brukt. Det ser ut til at du har oppgitt et kontonummer i stedet for en kupongkode. Hvis du vil endre den aktive kontoen, må du først logge ut. Kupongkoden er løst inn. - VPN-tillatelse ble avvist under opprettelsen av tunnelen. Prøv å koble til igjen. Trykk på koble til for å be om VPN-tillatelse Feil med VPN-tillatelse Dette skal vi følge opp. diff --git a/android/lib/resource/src/main/res/values-nl/strings.xml b/android/lib/resource/src/main/res/values-nl/strings.xml index 75cff3381cbf..95a52ae7d1ee 100644 --- a/android/lib/resource/src/main/res/values-nl/strings.xml +++ b/android/lib/resource/src/main/res/values-nl/strings.xml @@ -378,7 +378,6 @@ Vouchercode is al gebruikt. Het lijkt erop dat u een accountnummer hebt ingevoerd in plaats van een vouchercode. Als u het actieve account wilt wijzigen, meld u dan eerst af. Voucher is ingewisseld. - VPN-toestemming is geweigerd tijdens maken van de tunnel. Probeer opnieuw verbinding te maken. Druk op Verbinding maken om VPN-toestemming te verzoeken VPN-machtigingsfout We gaan het bekijken. diff --git a/android/lib/resource/src/main/res/values-pl/strings.xml b/android/lib/resource/src/main/res/values-pl/strings.xml index 99638266c729..2633bc6a1918 100644 --- a/android/lib/resource/src/main/res/values-pl/strings.xml +++ b/android/lib/resource/src/main/res/values-pl/strings.xml @@ -378,7 +378,6 @@ Kod z tego kuponu został już użyty. Wygląda na to, że wpisano numer konta zamiast kodu kuponu. Jeśli chcesz zmienić aktywne konto, najpierw się wyloguj. Kupon został zrealizowany. - Uprawnienie VPN zostało odrzucone podczas tworzenia tunelu. Spróbuj połączyć się ponownie. Naciśnij przycisk Połącz, aby zażądać uprawnienia VPN Błąd uprawnienia VPN Sprawdzimy to. diff --git a/android/lib/resource/src/main/res/values-pt/strings.xml b/android/lib/resource/src/main/res/values-pt/strings.xml index fbacfe3e371e..f7a0b1f0f057 100644 --- a/android/lib/resource/src/main/res/values-pt/strings.xml +++ b/android/lib/resource/src/main/res/values-pt/strings.xml @@ -378,7 +378,6 @@ O código do voucher já foi utilizado. Parece que introduziu um número de conta em vez de um código de voucher. Se pretender alterar a conta ativa, termine a sessão primeiro. O voucher foi reclamado com sucesso. - A transmissão foi negada durante a criação do túnel. Tente fazer novamente a ligação. Prima \"ligar\" para solicitar a permissão de VPN Erro de permissão da VPN Vamos analisar esta situação. diff --git a/android/lib/resource/src/main/res/values-ru/strings.xml b/android/lib/resource/src/main/res/values-ru/strings.xml index d40500b53c39..6ab83b64553b 100644 --- a/android/lib/resource/src/main/res/values-ru/strings.xml +++ b/android/lib/resource/src/main/res/values-ru/strings.xml @@ -378,7 +378,6 @@ Этот код ваучера уже использовался. Вы ввели номер учетной записи вместо кода ваучера. Чтобы изменить активную учетную запись, сначала выйдите из системы. Ваучер погашен. - При создании туннеля в доступе к VPN было отказано. Попробуйте подключиться снова. Чтобы запросить разрешение для VPN, нажмите «Подключить» Ошибка разрешения для VPN Мы рассмотрим эту проблему. diff --git a/android/lib/resource/src/main/res/values-sv/strings.xml b/android/lib/resource/src/main/res/values-sv/strings.xml index 728aad3752f8..63463d3d0842 100644 --- a/android/lib/resource/src/main/res/values-sv/strings.xml +++ b/android/lib/resource/src/main/res/values-sv/strings.xml @@ -378,7 +378,6 @@ Kupongkoden har redan använts. Det verkar som om du angett ett kontonummer istället för en kupongkod. Logga först ut om du vill ändra den aktiva koden. Kupongen har lösts in. - VPN-behörighet nekades när tunneln skapades. Försök att ansluta igen. Tryck på anslut för att begära VPN-behörighet Behörighetsfel med VPN Vi kommer att undersöka detta. diff --git a/android/lib/resource/src/main/res/values-th/strings.xml b/android/lib/resource/src/main/res/values-th/strings.xml index 35421721c9a7..6d9a6a05b134 100644 --- a/android/lib/resource/src/main/res/values-th/strings.xml +++ b/android/lib/resource/src/main/res/values-th/strings.xml @@ -378,7 +378,6 @@ รหัสบัตรกำนัลถูกใช้ไปแล้ว ดูเหมือนว่า คุณได้ป้อนหมายเลขบัญชีแทนรหัสบัตรกำนัล หากคุณต้องการเปลี่ยนบัญชีที่ใช้งานอยู่ โปรดออกจากระบบก่อน แลกบัตรกำนัลสำเร็จแล้ว - การให้สิทธิ์ VPN ถูกปฏิเสธ ในขณะที่สร้างอุโมงค์ โปรดลองเชื่อมต่อใหม่อีกครั้ง กรุณากดเชื่อมต่อ เพื่อขออนุญาตสิทธิ์ VPN เกิดข้อผิดพลาดในการอนุญาต VPN เราจะตรวจสอบปัญหานี้ diff --git a/android/lib/resource/src/main/res/values-tr/strings.xml b/android/lib/resource/src/main/res/values-tr/strings.xml index ec2c387b6aa1..565d28eda518 100644 --- a/android/lib/resource/src/main/res/values-tr/strings.xml +++ b/android/lib/resource/src/main/res/values-tr/strings.xml @@ -378,7 +378,6 @@ Kupon kodu zaten kullanılmış. Kupon kodu yerine hesap numarası girdiniz. Aktif hesabı değiştirmek istiyorsanız lütfen önce çıkış yapın. Kupon başarıyla kullanıldı. - Tünel oluşturulurken VPN izni reddedildi. Lütfen tekrar bağlanmayı deneyin. VPN izni istemek için lütfen bağlantıya dokunun VPN izin hatası Bunu araştıracağız. diff --git a/android/lib/resource/src/main/res/values-zh-rCN/strings.xml b/android/lib/resource/src/main/res/values-zh-rCN/strings.xml index 88eb74243e3c..8dbbe5d334ab 100644 --- a/android/lib/resource/src/main/res/values-zh-rCN/strings.xml +++ b/android/lib/resource/src/main/res/values-zh-rCN/strings.xml @@ -378,7 +378,6 @@ 该优惠券码已被使用。 您输入的似乎是帐号,而不是代金券码。如果您想更改有效帐户,请先退出登录。 优惠券已成功兑换。 - 创建隧道时,VPN 权限被拒绝。请尝试重新连接。 请按“连接”以请求 VPN 权限 VPN 权限错误 我们将对此进行调查。 diff --git a/android/lib/resource/src/main/res/values-zh-rTW/strings.xml b/android/lib/resource/src/main/res/values-zh-rTW/strings.xml index 47eec089523f..582d2594ea93 100644 --- a/android/lib/resource/src/main/res/values-zh-rTW/strings.xml +++ b/android/lib/resource/src/main/res/values-zh-rTW/strings.xml @@ -378,7 +378,6 @@ 此憑證兌換碼已有人用過。 您輸入的似乎是帳戶,而不是憑證代碼。如果您想變更有效帳戶,請先登出。 憑證已成功兌換。 - 建立通道時,VPN 權限被拒絕。請嘗試重新連線。 請按「連線」請求 VPN 權限 VPN 權限錯誤 我們會對此進行調查。 diff --git a/android/lib/resource/src/main/res/values/strings.xml b/android/lib/resource/src/main/res/values/strings.xml index 678c67834c11..5cb3436a8543 100644 --- a/android/lib/resource/src/main/res/values/strings.xml +++ b/android/lib/resource/src/main/res/values/strings.xml @@ -116,7 +116,7 @@ Unable to apply firewall rules. Please troubleshoot or send a problem report. Unable to set system DNS server. Please send a problem report. Unable to start tunnel connection. Please send a problem report. - VPN permission was denied when creating the tunnel. Please try connecting again. + VPN permission was denied or another app has \"Always-on VPN\" enabled No servers match your settings, try changing server or other settings. Valid WireGuard key is missing. Manage keys under Advanced settings. Enter IP diff --git a/desktop/packages/mullvad-vpn/locales/messages.pot b/desktop/packages/mullvad-vpn/locales/messages.pot index 841797440cde..8dbd347036e0 100644 --- a/desktop/packages/mullvad-vpn/locales/messages.pot +++ b/desktop/packages/mullvad-vpn/locales/messages.pot @@ -2745,7 +2745,7 @@ msgstr "" msgid "VPN permission error" msgstr "" -msgid "VPN permission was denied when creating the tunnel. Please try connecting again." +msgid "VPN permission was denied or another app has \"Always-on VPN\" enabled" msgstr "" msgid "VPN tunnel status"