aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/start/ErrorNotificationFragment.kt6
-rw-r--r--app/src/main/java/org/pacien/tincapp/context/App.kt16
-rw-r--r--app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt22
-rw-r--r--app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt60
-rw-r--r--app/src/main/java/org/pacien/tincapp/storageprovider/BrowseFilesIntents.kt6
-rw-r--r--app/src/main/res/layout/start_error_notification.xml30
-rw-r--r--app/src/main/res/values/strings.xml2
7 files changed, 125 insertions, 17 deletions
diff --git a/app/src/main/java/org/pacien/tincapp/activities/start/ErrorNotificationFragment.kt b/app/src/main/java/org/pacien/tincapp/activities/start/ErrorNotificationFragment.kt
index 08dab8d..f629623 100644
--- a/app/src/main/java/org/pacien/tincapp/activities/start/ErrorNotificationFragment.kt
+++ b/app/src/main/java/org/pacien/tincapp/activities/start/ErrorNotificationFragment.kt
@@ -1,6 +1,6 @@
1/* 1/*
2 * Tinc Mesh VPN: Android client and user interface 2 * Tinc Mesh VPN: Android client and user interface
3 * Copyright (C) 2017-2023 Euxane P. TRAN-GIRARD 3 * Copyright (C) 2017-2024 Euxane P. TRAN-GIRARD
4 * 4 *
5 * This program is free software: you can redistribute it and/or modify 5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -27,6 +27,8 @@ import org.pacien.tincapp.activities.BaseFragment
27import org.pacien.tincapp.context.App 27import org.pacien.tincapp.context.App
28import org.pacien.tincapp.context.AppNotificationManager 28import org.pacien.tincapp.context.AppNotificationManager
29import org.pacien.tincapp.databinding.StartErrorNotificationBinding 29import org.pacien.tincapp.databinding.StartErrorNotificationBinding
30import org.pacien.tincapp.storageprovider.BrowseFilesIntents
31import org.pacien.tincapp.storageprovider.FilesDocumentsProvider
30 32
31/** 33/**
32 * @author euxane 34 * @author euxane
@@ -56,5 +58,7 @@ class ErrorNotificationFragment : BaseFragment() {
56 val maybeError = notificationManager.getError() 58 val maybeError = notificationManager.getError()
57 viewBinding.errorNotification = maybeError 59 viewBinding.errorNotification = maybeError
58 viewBinding.openManualAction = { App.openURL(maybeError?.manualLink!!) } 60 viewBinding.openManualAction = { App.openURL(maybeError?.manualLink!!) }
61 viewBinding.openConfigDirAction = { openDocumentTree(BrowseFilesIntents.networkConfigDirDocId(maybeError?.configDir)) }
62 viewBinding.openLogDirAction = { openDocumentTree(FilesDocumentsProvider.VIRTUAL_ROOT_LOGS) }
59 } 63 }
60} 64}
diff --git a/app/src/main/java/org/pacien/tincapp/context/App.kt b/app/src/main/java/org/pacien/tincapp/context/App.kt
index 6145c65..e6402d2 100644
--- a/app/src/main/java/org/pacien/tincapp/context/App.kt
+++ b/app/src/main/java/org/pacien/tincapp/context/App.kt
@@ -70,8 +70,20 @@ class App : Application() {
70 .packageManager 70 .packageManager
71 .getApplicationInfo(BuildConfig.APPLICATION_ID, 0) 71 .getApplicationInfo(BuildConfig.APPLICATION_ID, 0)
72 72
73 fun alert(@StringRes title: Int, msg: String, manualLink: String? = null) = 73 fun alert(
74 notificationManager.notifyError(appContext!!.getString(title), msg, manualLink) 74 @StringRes title: Int,
75 msg: String,
76 manualLink: String? = null,
77 configDir: String? = null,
78 proposeLogs: Boolean = false,
79 ) =
80 notificationManager.notifyError(
81 appContext!!.getString(title),
82 msg,
83 manualLink,
84 configDir,
85 proposeLogs,
86 )
75 87
76 fun openURL(url: String) { 88 fun openURL(url: String) {
77 val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) 89 val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
diff --git a/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt b/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt
index c7a5ade..f4332e9 100644
--- a/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt
+++ b/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt
@@ -1,6 +1,6 @@
1/* 1/*
2 * Tinc Mesh VPN: Android client and user interface 2 * Tinc Mesh VPN: Android client and user interface
3 * Copyright (C) 2017-2023 Euxane P. TRAN-GIRARD 3 * Copyright (C) 2017-2024 Euxane P. TRAN-GIRARD
4 * 4 *
5 * This program is free software: you can redistribute it and/or modify 5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -28,7 +28,9 @@ class AppNotificationManager(private val context: Context) {
28 data class ErrorNotification( 28 data class ErrorNotification(
29 val title: String, 29 val title: String,
30 val message: String, 30 val message: String,
31 val manualLink: String? 31 val manualLink: String?,
32 val configDir: String?,
33 val proposeLogs: Boolean,
32 ) 34 )
33 35
34 companion object { 36 companion object {
@@ -36,6 +38,8 @@ class AppNotificationManager(private val context: Context) {
36 private const val STORE_KEY_TITLE = "title" 38 private const val STORE_KEY_TITLE = "title"
37 private const val STORE_KEY_MESSAGE = "message" 39 private const val STORE_KEY_MESSAGE = "message"
38 private const val STORE_KEY_MANUAL_LINK = "manual_link" 40 private const val STORE_KEY_MANUAL_LINK = "manual_link"
41 private const val STORE_CONFIG_DIR = "config_dir"
42 private const val STORE_PROPOSE_LOGS = "propose_logs_dir"
39 } 43 }
40 44
41 private val store by lazy { context.getSharedPreferences(STORE_NAME, Context.MODE_PRIVATE)!! } 45 private val store by lazy { context.getSharedPreferences(STORE_NAME, Context.MODE_PRIVATE)!! }
@@ -46,16 +50,26 @@ class AppNotificationManager(private val context: Context) {
46 return ErrorNotification( 50 return ErrorNotification(
47 store.getString(STORE_KEY_TITLE, null)!!, 51 store.getString(STORE_KEY_TITLE, null)!!,
48 store.getString(STORE_KEY_MESSAGE, null)!!, 52 store.getString(STORE_KEY_MESSAGE, null)!!,
49 store.getString(STORE_KEY_MANUAL_LINK, null) 53 store.getString(STORE_KEY_MANUAL_LINK, null),
54 store.getString(STORE_CONFIG_DIR, null),
55 store.getBoolean(STORE_PROPOSE_LOGS, false),
50 ) 56 )
51 } 57 }
52 58
53 fun notifyError(title: String, message: String, manualLink: String? = null) { 59 fun notifyError(
60 title: String,
61 message: String,
62 manualLink: String? = null,
63 configDir: String? = null,
64 proposeLogs: Boolean = false,
65 ) {
54 store 66 store
55 .edit() 67 .edit()
56 .putString(STORE_KEY_TITLE, title) 68 .putString(STORE_KEY_TITLE, title)
57 .putString(STORE_KEY_MESSAGE, message) 69 .putString(STORE_KEY_MESSAGE, message)
58 .putString(STORE_KEY_MANUAL_LINK, manualLink) 70 .putString(STORE_KEY_MANUAL_LINK, manualLink)
71 .putString(STORE_CONFIG_DIR, configDir)
72 .putBoolean(STORE_PROPOSE_LOGS, proposeLogs)
59 .apply() 73 .apply()
60 } 74 }
61 75
diff --git a/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt b/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
index 47ba0ec..77d7e96 100644
--- a/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
+++ b/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
@@ -123,11 +123,23 @@ class TincVpnService : VpnService() {
123 val interfaceCfg = try { 123 val interfaceCfg = try {
124 VpnInterfaceConfiguration.fromIfaceConfiguration(AppPaths.existing(AppPaths.netConfFile(netName))) 124 VpnInterfaceConfiguration.fromIfaceConfiguration(AppPaths.existing(AppPaths.netConfFile(netName)))
125 } catch (e: FileNotFoundException) { 125 } catch (e: FileNotFoundException) {
126 return reportError(resources.getString(R.string.notification_error_message_network_config_not_found_format, e.defaultMessage()), e, "configuration") 126 return reportError(
127 resources.getString(R.string.notification_error_message_network_config_not_found_format, e.defaultMessage()),
128 e,
129 docTopic = "configuration"
130 )
127 } catch (e: ConversionException) { 131 } catch (e: ConversionException) {
128 return reportError(resources.getString(R.string.notification_error_message_network_config_invalid_format, e.defaultMessage()), e, "network-interface") 132 return reportError(
133 resources.getString(R.string.notification_error_message_network_config_invalid_format, e.defaultMessage()),
134 e,
135 docTopic = "network-interface",
136 )
129 } catch (e: Exception) { 137 } catch (e: Exception) {
130 return reportError(resources.getString(R.string.notification_error_message_could_not_read_network_configuration_format, e.defaultMessage()), e) 138 return reportError(
139 resources.getString(R.string.notification_error_message_could_not_read_network_configuration_format, e.defaultMessage()),
140 e,
141 configDir = netName,
142 )
131 } 143 }
132 144
133 val deviceFd = try { 145 val deviceFd = try {
@@ -138,11 +150,24 @@ class TincVpnService : VpnService() {
138 .also { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) it.setMetered(false) } 150 .also { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) it.setMetered(false) }
139 .establish()!! 151 .establish()!!
140 } catch (e: IllegalArgumentException) { 152 } catch (e: IllegalArgumentException) {
141 return reportError(resources.getString(R.string.notification_error_message_network_config_invalid_format, e.defaultMessage()), e, "network-interface") 153 return reportError(
154 resources.getString(R.string.notification_error_message_network_config_invalid_format, e.defaultMessage()),
155 e,
156 docTopic = "network-interface",
157 configDir = netName,
158 )
142 } catch (e: NullPointerException) { 159 } catch (e: NullPointerException) {
143 return reportError(resources.getString(R.string.notification_error_message_could_not_bind_iface), e) 160 return reportError(
161 resources.getString(R.string.notification_error_message_could_not_bind_iface),
162 e,
163 proposeLogs = true,
164 )
144 } catch (e: Exception) { 165 } catch (e: Exception) {
145 return reportError(resources.getString(R.string.notification_error_message_could_not_configure_iface, e.defaultMessage()), e) 166 return reportError(
167 resources.getString(R.string.notification_error_message_could_not_configure_iface, e.defaultMessage()),
168 e,
169 proposeLogs = true,
170 )
146 }