diff options
-rw-r--r-- | app/build.gradle | 1 | ||||
-rw-r--r-- | app/src/main/AndroidManifest.xml | 1 | ||||
-rw-r--r-- | app/src/main/java/org/pacien/tincapp/context/App.kt | 13 | ||||
-rw-r--r-- | app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt | 84 | ||||
-rw-r--r-- | app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt | 2 | ||||
-rw-r--r-- | app/src/main/java/org/pacien/tincapp/utils/ProgressModal.kt | 2 | ||||
-rw-r--r-- | app/src/main/res/drawable/ic_warning_primary_24dp.xml | 28 | ||||
-rw-r--r-- | app/src/main/res/values/strings.xml | 2 |
8 files changed, 123 insertions, 10 deletions
diff --git a/app/build.gradle b/app/build.gradle index bc5ae95..bfe3944 100644 --- a/app/build.gradle +++ b/app/build.gradle | |||
@@ -55,6 +55,7 @@ dependencies { | |||
55 | 55 | ||
56 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" | 56 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" |
57 | implementation 'net.sourceforge.streamsupport:streamsupport-cfuture:1.6.3' | 57 | implementation 'net.sourceforge.streamsupport:streamsupport-cfuture:1.6.3' |
58 | implementation "com.android.support:support-compat:27.1.1" | ||
58 | implementation 'com.android.support:design:27.1.1' | 59 | implementation 'com.android.support:design:27.1.1' |
59 | implementation 'com.google.zxing:android-integration:3.3.0' | 60 | implementation 'com.google.zxing:android-integration:3.3.0' |
60 | implementation 'org.bouncycastle:bcpkix-jdk15on:1.59' | 61 | implementation 'org.bouncycastle:bcpkix-jdk15on:1.59' |
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bf8e9d7..d96fba6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml | |||
@@ -23,7 +23,6 @@ | |||
23 | package="org.pacien.tincapp"> | 23 | package="org.pacien.tincapp"> |
24 | 24 | ||
25 | <uses-permission android:name="android.permission.INTERNET"/> | 25 | <uses-permission android:name="android.permission.INTERNET"/> |
26 | <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> | ||
27 | 26 | ||
28 | <application | 27 | <application |
29 | android:name="org.pacien.tincapp.context.App" | 28 | android:name="org.pacien.tincapp.context.App" |
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 2d9151e..88308ba 100644 --- a/app/src/main/java/org/pacien/tincapp/context/App.kt +++ b/app/src/main/java/org/pacien/tincapp/context/App.kt | |||
@@ -25,8 +25,6 @@ import android.net.Uri | |||
25 | import android.os.Build | 25 | import android.os.Build |
26 | import android.os.Handler | 26 | import android.os.Handler |
27 | import android.support.annotation.StringRes | 27 | import android.support.annotation.StringRes |
28 | import android.support.v7.app.AlertDialog | ||
29 | import android.view.WindowManager | ||
30 | import org.pacien.tincapp.BuildConfig | 28 | import org.pacien.tincapp.BuildConfig |
31 | import org.pacien.tincapp.R | 29 | import org.pacien.tincapp.R |
32 | import org.slf4j.LoggerFactory | 30 | import org.slf4j.LoggerFactory |
@@ -59,16 +57,13 @@ class App : Application() { | |||
59 | private var appContext: Context? = null | 57 | private var appContext: Context? = null |
60 | private var handler: Handler? = null | 58 | private var handler: Handler? = null |
61 | 59 | ||
60 | val notificationManager: AppNotificationManager by lazy { AppNotificationManager(appContext!!) } | ||
61 | |||
62 | fun getContext() = appContext!! | 62 | fun getContext() = appContext!! |
63 | fun getResources() = getContext().resources!! | 63 | fun getResources() = getContext().resources!! |
64 | 64 | ||
65 | fun alert(@StringRes title: Int, msg: String, manualLink: String? = null) = handler!!.post { | 65 | fun alert(@StringRes title: Int, msg: String, manualLink: String? = null) = |
66 | AlertDialog.Builder(getContext(), R.style.Theme_AppCompat_Dialog) | 66 | notificationManager.notifyError(appContext!!.getString(title), msg, manualLink) |
67 | .setTitle(title).setMessage(msg) | ||
68 | .apply { if (manualLink != null) setNeutralButton(R.string.action_open_manual) { _, _ -> openURL(manualLink) } } | ||
69 | .setPositiveButton(R.string.action_close) { _, _ -> Unit } | ||
70 | .create().apply { window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR) }.show() | ||
71 | } | ||
72 | 67 | ||
73 | fun openURL(url: String) { | 68 | fun openURL(url: String) { |
74 | val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) | 69 | 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 new file mode 100644 index 0000000..0f9092a --- /dev/null +++ b/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * tinc app, an Android binding and user interface for the tinc mesh VPN daemon | ||
3 | * Copyright (C) 2017-2018 Pacien TRAN-GIRARD | ||
4 | * | ||
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 | ||
7 | * the Free Software Foundation, either version 3 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | package org.pacien.tincapp.context | ||
20 | |||
21 | import android.app.NotificationChannel | ||
22 | import android.app.NotificationManager | ||
23 | import android.app.PendingIntent | ||
24 | import android.content.Context | ||
25 | import android.content.Intent | ||
26 | import android.net.Uri | ||
27 | import android.os.Build | ||
28 | import android.support.annotation.RequiresApi | ||
29 | import android.support.v4.app.NotificationCompat | ||
30 | import android.support.v4.app.NotificationManagerCompat | ||
31 | import org.pacien.tincapp.R | ||
32 | |||
33 | /** | ||
34 | * @author pacien | ||
35 | */ | ||
36 | class AppNotificationManager(private val context: Context) { | ||
37 | companion object { | ||
38 | private const val CHANNEL_ID = "org.pacien.tincapp.notification.channels.error" | ||
39 | private const val ERROR_NOTIFICATION_ID = 0 | ||
40 | } | ||
41 | |||
42 | init { | ||
43 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) registerChannel() | ||
44 | } | ||
45 | |||
46 | fun notifyError(title: String, message: String, manualLink: String? = null) { | ||
47 | val notification = NotificationCompat.Builder(context, CHANNEL_ID) | ||
48 | .setSmallIcon(R.drawable.ic_warning_primary_24dp) | ||
49 | .setContentTitle(title) | ||
50 | .setContentText(message) | ||
51 | .setStyle(NotificationCompat.BigTextStyle().bigText(message)) | ||
52 | .setHighPriority() | ||
53 | .setAutoCancel(true) | ||
54 | .apply { if (manualLink != null) setManualLink(manualLink) } | ||
55 | .build() | ||
56 | |||
57 | NotificationManagerCompat.from(context) | ||
58 | .notify(ERROR_NOTIFICATION_ID, notification) | ||
59 | } | ||
60 | |||
61 | fun dismissAll() { | ||
62 | NotificationManagerCompat.from(context).cancelAll() | ||
63 | } | ||
64 | |||
65 | @RequiresApi(Build.VERSION_CODES.O) | ||
66 | private fun registerChannel() { | ||
67 | val name = context.getString(R.string.notification_channel_error_name) | ||
68 | val importance = NotificationManager.IMPORTANCE_HIGH | ||
69 | val channel = NotificationChannel(CHANNEL_ID, name, importance) | ||
70 | val notificationManager = context.getSystemService(NotificationManager::class.java) | ||
71 | notificationManager.createNotificationChannel(channel) | ||
72 | } | ||
73 | |||
74 | private fun NotificationCompat.Builder.setHighPriority() = apply { | ||
75 | priority = NotificationCompat.PRIORITY_MAX | ||
76 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) setDefaults(NotificationCompat.DEFAULT_SOUND) // force heads-up notification | ||
77 | } | ||
78 | |||
79 | private fun NotificationCompat.Builder.setManualLink(manualLink: String) = apply { | ||
80 | val intent = Intent(Intent.ACTION_VIEW, Uri.parse(manualLink)) | ||
81 | val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0) | ||
82 | addAction(R.drawable.ic_help_primary_24dp, context.getString(R.string.action_open_manual), pendingIntent) | ||
83 | } | ||
84 | } | ||
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 30d7c8b..6ed9a34 100644 --- a/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt +++ b/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt | |||
@@ -197,6 +197,8 @@ class TincVpnService : VpnService() { | |||
197 | fun isConnected() = !(daemon?.isDone ?: true) | 197 | fun isConnected() = !(daemon?.isDone ?: true) |
198 | 198 | ||
199 | fun connect(netName: String, passphrase: String? = null) { | 199 | fun connect(netName: String, passphrase: String? = null) { |
200 | App.notificationManager.dismissAll() | ||
201 | |||
200 | App.getContext().startService( | 202 | App.getContext().startService( |
201 | Intent(App.getContext(), TincVpnService::class.java) | 203 | Intent(App.getContext(), TincVpnService::class.java) |
202 | .setAction(Actions.ACTION_CONNECT) | 204 | .setAction(Actions.ACTION_CONNECT) |
diff --git a/app/src/main/java/org/pacien/tincapp/utils/ProgressModal.kt b/app/src/main/java/org/pacien/tincapp/utils/ProgressModal.kt index 379e3af..6bf02d5 100644 --- a/app/src/main/java/org/pacien/tincapp/utils/ProgressModal.kt +++ b/app/src/main/java/org/pacien/tincapp/utils/ProgressModal.kt | |||
@@ -27,6 +27,8 @@ import android.widget.TextView | |||
27 | import org.pacien.tincapp.R | 27 | import org.pacien.tincapp.R |
28 | 28 | ||
29 | /** | 29 | /** |
30 | * An indefinite progress dialog replacing the deprecated `android.app.ProgressDialog`. | ||
31 | * | ||
30 | * @author pacien | 32 | * @author pacien |
31 | */ | 33 | */ |
32 | object ProgressModal { | 34 | object ProgressModal { |
diff --git a/app/src/main/res/drawable/ic_warning_primary_24dp.xml b/app/src/main/res/drawable/ic_warning_primary_24dp.xml new file mode 100644 index 0000000..d8fa0fe --- /dev/null +++ b/app/src/main/res/drawable/ic_warning_primary_24dp.xml | |||
@@ -0,0 +1,28 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | |||
3 | <!-- | ||
4 | * Material design icon | ||
5 | * Copyright 2017 Google Inc. | ||
6 | * | ||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | * you may not use this file except in compliance with the License. | ||
9 | * You may obtain a copy of the License at | ||
10 | * | ||
11 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | * | ||
13 | * Unless required by applicable law or agreed to in writing, software | ||
14 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | * See the License for the specific language governing permissions and | ||
17 | * limitations under the License. | ||
18 | --> | ||
19 | |||
20 | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||