diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9cf3229..e5231bb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,6 +5,7 @@
+
+ android:theme="@style/Theme.Yggdrasil"
+ android:largeHeap="true">
@@ -57,6 +59,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/BootUpReceiver.kt b/app/src/main/java/eu/neilalexander/yggdrasil/BootUpReceiver.kt
new file mode 100644
index 0000000..2ca3629
--- /dev/null
+++ b/app/src/main/java/eu/neilalexander/yggdrasil/BootUpReceiver.kt
@@ -0,0 +1,40 @@
+package eu.neilalexander.yggdrasil
+
+import android.app.NotificationManager
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.net.VpnService
+import android.util.Log
+import androidx.preference.PreferenceManager
+
+class BootUpReceiver : BroadcastReceiver() {
+
+ companion object {
+ const val TAG = "BootUpReceiver"
+ }
+
+ override fun onReceive(context: Context, intent: Intent) {
+ if (intent.action != Intent.ACTION_BOOT_COMPLETED) {
+ Log.w(TAG, "Wrong action: ${intent.action}")
+ }
+ val preferences = PreferenceManager.getDefaultSharedPreferences(context)
+ if (!preferences.getBoolean(PREF_KEY_ENABLED, false)) {
+ Log.i(TAG, "Yggdrasil disabled, not starting service")
+ return
+ }
+ Log.i(TAG, "Yggdrasil enabled, starting service")
+ val serviceIntent = Intent(context, PacketTunnelProvider::class.java)
+ serviceIntent.action = PacketTunnelProvider.ACTION_START
+
+ val vpnIntent = VpnService.prepare(context)
+ if (vpnIntent != null) {
+ Log.i(TAG, "Need to ask for VPN permission")
+ val notification = createPermissionMissingNotification(context)
+ val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ manager.notify(444, notification)
+ } else {
+ context.startService(serviceIntent)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/DnsActivity.kt b/app/src/main/java/eu/neilalexander/yggdrasil/DnsActivity.kt
index d95496b..7ef32c4 100644
--- a/app/src/main/java/eu/neilalexander/yggdrasil/DnsActivity.kt
+++ b/app/src/main/java/eu/neilalexander/yggdrasil/DnsActivity.kt
@@ -59,7 +59,7 @@ class DnsActivity : AppCompatActivity() {
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog))
builder.setTitle(getString(R.string.dns_add_server_dialog_title))
builder.setView(view)
- builder.setPositiveButton(getString(R.string.add)) { dialog, _ ->
+ builder.setPositiveButton(getString(R.string.add)) { _, _ ->
val server = input.text.toString()
if (!servers.contains(server)) {
servers.add(server)
diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/GlobalApplication.kt b/app/src/main/java/eu/neilalexander/yggdrasil/GlobalApplication.kt
index 341cd99..b2f02b4 100644
--- a/app/src/main/java/eu/neilalexander/yggdrasil/GlobalApplication.kt
+++ b/app/src/main/java/eu/neilalexander/yggdrasil/GlobalApplication.kt
@@ -10,6 +10,7 @@ import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
const val PREF_KEY_ENABLED = "enabled"
+const val MAIN_CHANNEL_ID = "Yggdrasil Service"
class GlobalApplication: Application(), YggStateReceiver.StateReceiver {
private lateinit var config: ConfigurationProxy
@@ -62,21 +63,7 @@ class GlobalApplication: Application(), YggStateReceiver.StateReceiver {
}
fun createServiceNotification(context: Context, state: State): Notification {
- // Create the NotificationChannel, but only on API 26+ because
- // the NotificationChannel class is new and not in the support library
- val channelId = "Foreground Service"
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- val name = context.getString(R.string.channel_name)
- val descriptionText = context.getString(R.string.channel_description)
- val importance = NotificationManager.IMPORTANCE_MIN
- val channel = NotificationChannel(channelId, name, importance).apply {
- description = descriptionText
- }
- // Register the channel with the system
- val notificationManager: NotificationManager =
- context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
- notificationManager.createNotificationChannel(channel)
- }
+ createNotificationChannels(context)
val intent = Intent(context, MainActivity::class.java).apply {
this.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
@@ -90,11 +77,46 @@ fun createServiceNotification(context: Context, state: State): Notification {
else -> context.getText(R.string.tile_disabled)
}
- return NotificationCompat.Builder(context, channelId)
+ return NotificationCompat.Builder(context, MAIN_CHANNEL_ID)
.setShowWhen(false)
.setContentTitle(text)
.setSmallIcon(R.drawable.ic_tile_icon)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_MIN)
.build()
+}
+
+fun createPermissionMissingNotification(context: Context): Notification {
+ createNotificationChannels(context)
+ val intent = Intent(context, MainActivity::class.java).apply {
+ this.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+ }
+ val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+
+ return NotificationCompat.Builder(context, MAIN_CHANNEL_ID)
+ .setShowWhen(false)
+ .setContentTitle(context.getText(R.string.app_name))
+ .setContentText(context.getText(R.string.permission_notification_text))
+ .setSmallIcon(R.drawable.ic_tile_icon)
+ .setContentIntent(pendingIntent)
+ .setAutoCancel(true)
+ .setPriority(NotificationCompat.PRIORITY_DEFAULT)
+ .build()
+}
+
+private fun createNotificationChannels(context: Context) {
+ // Create the NotificationChannel, but only on API 26+ because
+ // the NotificationChannel class is new and not in the support library
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val name = context.getString(R.string.channel_name)
+ val descriptionText = context.getString(R.string.channel_description)
+ val importance = NotificationManager.IMPORTANCE_MIN
+ val channel = NotificationChannel(MAIN_CHANNEL_ID, name, importance).apply {
+ description = descriptionText
+ }
+ // Register the channel with the system
+ val notificationManager: NotificationManager =
+ context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ notificationManager.createNotificationChannel(channel)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/PacketTunnelProvider.kt b/app/src/main/java/eu/neilalexander/yggdrasil/PacketTunnelProvider.kt
index 4923a91..4e7067e 100644
--- a/app/src/main/java/eu/neilalexander/yggdrasil/PacketTunnelProvider.kt
+++ b/app/src/main/java/eu/neilalexander/yggdrasil/PacketTunnelProvider.kt
@@ -20,7 +20,7 @@ import kotlin.concurrent.thread
private const val TAG = "PacketTunnelProvider"
const val SERVICE_NOTIFICATION_ID = 1000
-class PacketTunnelProvider: VpnService() {
+open class PacketTunnelProvider: VpnService() {
companion object {
const val STATE_INTENT = "eu.neilalexander.yggdrasil.PacketTunnelProvider.STATE_MESSAGE"
@@ -68,9 +68,9 @@ class PacketTunnelProvider: VpnService() {
ACTION_CONNECT -> {
Log.d(TAG, "Connecting...")
if (started.get()) {
- connect();
+ connect()
} else {
- start();
+ start()
}
START_STICKY
}
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index e687b53..29f00ea 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -75,4 +75,5 @@
Баффало, США
Сервис VPN
Главный канал нотификаций сервиса
+ Нажмите здесь чтобы включить Yggdrasil.
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 13d0a90..a6d0538 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -75,4 +75,5 @@
Buffalo, US
VPN Service
Main channel for foreground notification
+ Tap here to enable Yggdrasil.
\ No newline at end of file