mirror of
				https://github.com/yggdrasil-network/yggdrasil-android.git
				synced 2025-11-04 11:15:08 +03:00 
			
		
		
		
	Added saving of enabled state, added some fixes and refactorings.
This commit is contained in:
		
							parent
							
								
									1152070fac
								
							
						
					
					
						commit
						631d321206
					
				
					 9 changed files with 133 additions and 40 deletions
				
			
		| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
    <uses-permission android:name="android.permission.INTERNET" />
 | 
			
		||||
    <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
 | 
			
		||||
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 | 
			
		||||
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
 | 
			
		||||
 | 
			
		||||
    <application
 | 
			
		||||
        android:name=".GlobalApplication"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ import android.view.ContextThemeWrapper
 | 
			
		|||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.*
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import com.google.android.material.textfield.TextInputEditText
 | 
			
		||||
 | 
			
		||||
const val KEY_DNS_SERVERS = "dns_servers"
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +86,7 @@ class DnsActivity : AppCompatActivity() {
 | 
			
		|||
            enableChromeFix.toggle()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        preferences = androidx.preference.PreferenceManager.getDefaultSharedPreferences(this.baseContext)
 | 
			
		||||
        preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext)
 | 
			
		||||
        val serverString = preferences.getString(KEY_DNS_SERVERS, "")
 | 
			
		||||
        servers = if (serverString!!.isNotEmpty()) {
 | 
			
		||||
            serverString.split(",").toMutableList()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,15 @@
 | 
			
		|||
package eu.neilalexander.yggdrasil
 | 
			
		||||
 | 
			
		||||
import android.app.Application
 | 
			
		||||
import android.app.*
 | 
			
		||||
import android.content.ComponentName
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.service.quicksettings.TileService
 | 
			
		||||
import androidx.annotation.RequiresApi
 | 
			
		||||
import androidx.core.app.NotificationCompat
 | 
			
		||||
 | 
			
		||||
const val PREF_KEY_ENABLED = "enabled"
 | 
			
		||||
 | 
			
		||||
class GlobalApplication: Application(), YggStateReceiver.StateReceiver {
 | 
			
		||||
    private lateinit var config: ConfigurationProxy
 | 
			
		||||
| 
						 | 
				
			
			@ -15,6 +20,7 @@ class GlobalApplication: Application(), YggStateReceiver.StateReceiver {
 | 
			
		|||
        super.onCreate()
 | 
			
		||||
        config = ConfigurationProxy(applicationContext)
 | 
			
		||||
        val callback = NetworkStateCallback(this)
 | 
			
		||||
        callback.register()
 | 
			
		||||
        val receiver = YggStateReceiver(this)
 | 
			
		||||
        receiver.register(this)
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +48,53 @@ class GlobalApplication: Application(), YggStateReceiver.StateReceiver {
 | 
			
		|||
        if (state != currentState) {
 | 
			
		||||
            val componentName = ComponentName(this, YggTileService::class.java)
 | 
			
		||||
            TileService.requestListeningState(this, componentName)
 | 
			
		||||
 | 
			
		||||
            if (state != State.Disabled) {
 | 
			
		||||
                val notification = createServiceNotification(this, state)
 | 
			
		||||
                val notificationManager: NotificationManager =
 | 
			
		||||
                    this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
 | 
			
		||||
                notificationManager.notify(SERVICE_NOTIFICATION_ID, notification)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            currentState = state
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
    val text = when (state) {
 | 
			
		||||
        State.Disabled -> context.getText(R.string.tile_disabled)
 | 
			
		||||
        State.Enabled -> context.getText(R.string.tile_enabled)
 | 
			
		||||
        State.Connected -> context.getText(R.string.tile_connected)
 | 
			
		||||
        else -> context.getText(R.string.tile_disabled)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return NotificationCompat.Builder(context, channelId)
 | 
			
		||||
        .setContentTitle(context.getText(R.string.app_name))
 | 
			
		||||
        .setContentText(text)
 | 
			
		||||
        .setSmallIcon(R.drawable.ic_tile_icon)
 | 
			
		||||
        .setContentIntent(pendingIntent)
 | 
			
		||||
        .setPriority(NotificationCompat.PRIORITY_MIN)
 | 
			
		||||
        .build()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +11,9 @@ import android.widget.TextView
 | 
			
		|||
import android.widget.Toast
 | 
			
		||||
import androidx.activity.result.contract.ActivityResultContracts
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import androidx.core.content.edit
 | 
			
		||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import eu.neilalexander.yggdrasil.PacketTunnelProvider.Companion.STATE_INTENT
 | 
			
		||||
import mobile.Mobile
 | 
			
		||||
import org.json.JSONArray
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +78,8 @@ class MainActivity : AppCompatActivity() {
 | 
			
		|||
                    startService(intent)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            val preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext)
 | 
			
		||||
            preferences.edit(commit = true) { putBoolean(PREF_KEY_ENABLED, isChecked) }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val enableYggdrasilPanel = findViewById<TableRow>(R.id.enableYggdrasilPanel)
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +127,7 @@ class MainActivity : AppCompatActivity() {
 | 
			
		|||
        LocalBroadcastManager.getInstance(this).registerReceiver(
 | 
			
		||||
            receiver, IntentFilter(STATE_INTENT)
 | 
			
		||||
        )
 | 
			
		||||
        val preferences = androidx.preference.PreferenceManager.getDefaultSharedPreferences(this.baseContext)
 | 
			
		||||
        val preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext)
 | 
			
		||||
        val serverString = preferences.getString(KEY_DNS_SERVERS, "")
 | 
			
		||||
        if (serverString!!.isNotEmpty()) {
 | 
			
		||||
            val servers = serverString.split(",")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,14 +3,43 @@ package eu.neilalexander.yggdrasil
 | 
			
		|||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.net.*
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private const val TAG = "Network"
 | 
			
		||||
 | 
			
		||||
class NetworkStateCallback(val context: Context) : ConnectivityManager.NetworkCallback() {
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
    override fun onAvailable(network: Network) {
 | 
			
		||||
        super.onAvailable(network)
 | 
			
		||||
        Log.d(TAG, "onAvailable")
 | 
			
		||||
 | 
			
		||||
        val preferences = PreferenceManager.getDefaultSharedPreferences(context)
 | 
			
		||||
        if (preferences.getBoolean(PREF_KEY_ENABLED, false)) {
 | 
			
		||||
            Thread {
 | 
			
		||||
                // The message often arrives before the connection is fully established
 | 
			
		||||
                Thread.sleep(1000)
 | 
			
		||||
                val intent = Intent(context, PacketTunnelProvider::class.java)
 | 
			
		||||
                intent.action = PacketTunnelProvider.ACTION_CONNECT
 | 
			
		||||
                try {
 | 
			
		||||
                    context.startService(intent)
 | 
			
		||||
                } catch (e: IllegalStateException) {
 | 
			
		||||
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
 | 
			
		||||
                        context.startForegroundService(intent)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }.start()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onLost(network: Network) {
 | 
			
		||||
        super.onLost(network)
 | 
			
		||||
        Log.d(TAG, "onLost")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun register() {
 | 
			
		||||
        val request = NetworkRequest.Builder()
 | 
			
		||||
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
 | 
			
		||||
            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
 | 
			
		||||
| 
						 | 
				
			
			@ -20,22 +49,4 @@ class NetworkStateCallback(val context: Context) : ConnectivityManager.NetworkCa
 | 
			
		|||
        val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
 | 
			
		||||
        manager.registerNetworkCallback(request, this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onAvailable(network: Network) {
 | 
			
		||||
        super.onAvailable(network)
 | 
			
		||||
        Log.d(TAG, "onAvailable")
 | 
			
		||||
 | 
			
		||||
        Thread {
 | 
			
		||||
            // The message often arrives before the connection is fully established
 | 
			
		||||
            Thread.sleep(1000)
 | 
			
		||||
            val intent = Intent(context, PacketTunnelProvider::class.java)
 | 
			
		||||
            intent.action = PacketTunnelProvider.ACTION_CONNECT
 | 
			
		||||
            context.startService(intent)
 | 
			
		||||
        }.start()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onLost(network: Network) {
 | 
			
		||||
        super.onLost(network)
 | 
			
		||||
        Log.d(TAG, "onLost")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,10 +2,12 @@ package eu.neilalexander.yggdrasil
 | 
			
		|||
 | 
			
		||||
import android.content.*
 | 
			
		||||
import android.net.VpnService
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.os.ParcelFileDescriptor
 | 
			
		||||
import android.system.OsConstants
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import eu.neilalexander.yggdrasil.YggStateReceiver.Companion.YGG_STATE_INTENT
 | 
			
		||||
import mobile.Yggdrasil
 | 
			
		||||
import org.json.JSONArray
 | 
			
		||||
| 
						 | 
				
			
			@ -16,6 +18,7 @@ import kotlin.concurrent.thread
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
private const val TAG = "PacketTunnelProvider"
 | 
			
		||||
const val SERVICE_NOTIFICATION_ID = 1000
 | 
			
		||||
 | 
			
		||||
class PacketTunnelProvider: VpnService() {
 | 
			
		||||
    companion object {
 | 
			
		||||
| 
						 | 
				
			
			@ -55,6 +58,11 @@ class PacketTunnelProvider: VpnService() {
 | 
			
		|||
            Log.d(TAG, "Intent is null")
 | 
			
		||||
            return START_NOT_STICKY
 | 
			
		||||
        }
 | 
			
		||||
        val preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext)
 | 
			
		||||
        if (!preferences.getBoolean(PREF_KEY_ENABLED, false)) {
 | 
			
		||||
            Log.d(TAG, "Service is disabled")
 | 
			
		||||
            return START_NOT_STICKY
 | 
			
		||||
        }
 | 
			
		||||
        return when (intent.action ?: ACTION_STOP) {
 | 
			
		||||
            ACTION_STOP -> {
 | 
			
		||||
                Log.d(TAG, "Stopping...")
 | 
			
		||||
| 
						 | 
				
			
			@ -89,6 +97,9 @@ class PacketTunnelProvider: VpnService() {
 | 
			
		|||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val notification = createServiceNotification(this, State.Enabled)
 | 
			
		||||
        startForeground(SERVICE_NOTIFICATION_ID, notification)
 | 
			
		||||
 | 
			
		||||
        Log.d(TAG, config.getJSON().toString())
 | 
			
		||||
        yggdrasil.startJSON(config.getJSONByteArray())
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -112,11 +123,11 @@ class PacketTunnelProvider: VpnService() {
 | 
			
		|||
        // If we don't set metered status of VPN it is considered as metered.
 | 
			
		||||
        // If we set it to false, then it will inherit this status from underlying network.
 | 
			
		||||
        // See: https://developer.android.com/reference/android/net/VpnService.Builder#setMetered(boolean)
 | 
			
		||||
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
 | 
			
		||||
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
 | 
			
		||||
            builder.setMetered(false)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val preferences = androidx.preference.PreferenceManager.getDefaultSharedPreferences(this.baseContext)
 | 
			
		||||
        val preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext)
 | 
			
		||||
        val serverString = preferences.getString(KEY_DNS_SERVERS, "")
 | 
			
		||||
        if (serverString!!.isNotEmpty()) {
 | 
			
		||||
            val servers = serverString.split(",")
 | 
			
		||||
| 
						 | 
				
			
			@ -207,6 +218,7 @@ class PacketTunnelProvider: VpnService() {
 | 
			
		|||
        intent.putExtra("state", STATE_DISABLED)
 | 
			
		||||
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
 | 
			
		||||
 | 
			
		||||
        stopForeground(true)
 | 
			
		||||
        stopSelf()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -236,10 +248,12 @@ class PacketTunnelProvider: VpnService() {
 | 
			
		|||
                val intent = Intent(YGG_STATE_INTENT)
 | 
			
		||||
                var state = STATE_ENABLED
 | 
			
		||||
                val dht = yggdrasil.dhtjson
 | 
			
		||||
                val dhtState = JSONArray(dht)
 | 
			
		||||
                val count = dhtState.length()
 | 
			
		||||
                if (count > 1)
 | 
			
		||||
                    state = STATE_CONNECTED
 | 
			
		||||
                if (dht != null && dht != "null") {
 | 
			
		||||
                    val dhtState = JSONArray(dht)
 | 
			
		||||
                    val count = dhtState.length()
 | 
			
		||||
                    if (count > 1)
 | 
			
		||||
                        state = STATE_CONNECTED
 | 
			
		||||
                }
 | 
			
		||||
                intent.putExtra("state", state)
 | 
			
		||||
                LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
 | 
			
		||||
                lastStateUpdate = curTime
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,8 @@ import android.service.quicksettings.Tile
 | 
			
		|||
import android.service.quicksettings.TileService
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import androidx.annotation.RequiresApi
 | 
			
		||||
import androidx.core.content.edit
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
 | 
			
		||||
private const val TAG = "TileService"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +65,11 @@ class YggTileService: TileService(), YggStateReceiver.StateReceiver {
 | 
			
		|||
 | 
			
		||||
    override fun onClick() {
 | 
			
		||||
        super.onClick()
 | 
			
		||||
        // Saving new state
 | 
			
		||||
        val preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext)
 | 
			
		||||
        val enabled = preferences.getBoolean(PREF_KEY_ENABLED, false)
 | 
			
		||||
        preferences.edit(commit = true) { putBoolean(PREF_KEY_ENABLED, !enabled) }
 | 
			
		||||
        // Starting or stopping VPN service
 | 
			
		||||
        val intent = Intent(this, PacketTunnelProvider::class.java)
 | 
			
		||||
        intent.action = PacketTunnelProvider.ACTION_TOGGLE
 | 
			
		||||
        startService(intent)
 | 
			
		||||
| 
						 | 
				
			
			@ -71,12 +78,11 @@ class YggTileService: TileService(), YggStateReceiver.StateReceiver {
 | 
			
		|||
    private fun updateTileState(state: State) {
 | 
			
		||||
        val tile = qsTile ?: return
 | 
			
		||||
        val oldState = tile.state
 | 
			
		||||
        tile.state = when (state) {
 | 
			
		||||
            State.Unknown -> Tile.STATE_UNAVAILABLE
 | 
			
		||||
            State.Disabled -> Tile.STATE_INACTIVE
 | 
			
		||||
            State.Enabled -> Tile.STATE_ACTIVE
 | 
			
		||||
            State.Connected -> Tile.STATE_ACTIVE
 | 
			
		||||
            State.Reconnecting -> Tile.STATE_ACTIVE
 | 
			
		||||
        val preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext)
 | 
			
		||||
        val enabled = preferences.getBoolean(PREF_KEY_ENABLED, false)
 | 
			
		||||
        tile.state = when (enabled) {
 | 
			
		||||
            false -> Tile.STATE_INACTIVE
 | 
			
		||||
            true -> Tile.STATE_ACTIVE
 | 
			
		||||
        }
 | 
			
		||||
        var changed = oldState != tile.state
 | 
			
		||||
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,8 +22,8 @@
 | 
			
		|||
    <string name="dns_one_server">1 сервер</string>
 | 
			
		||||
    <string name="dns_many_servers">%d сервера/серверов</string>
 | 
			
		||||
    <string name="dns_remove_title">Убрать %s?</string>
 | 
			
		||||
    <string name="main_no_connectivity">Нет подключения</string>
 | 
			
		||||
    <string name="main_enabled">Включено</string>
 | 
			
		||||
    <string name="main_no_connectivity">Включено (Нет подключения)</string>
 | 
			
		||||
    <string name="main_enabled">Подключено</string>
 | 
			
		||||
    <string name="main_disabled">Выключено</string>
 | 
			
		||||
    <string name="main_no_peers">Нет пиров</string>
 | 
			
		||||
    <string name="main_one_peer">1 пир</string>
 | 
			
		||||
| 
						 | 
				
			
			@ -66,10 +66,12 @@
 | 
			
		|||
    <string name="reset_configuration">Сбросить настройки</string>
 | 
			
		||||
    <string name="reset_configuration_hint">Сброс создаст полностью новые настройки. Это изменит ваш публичный ключ и адрес IP.</string>
 | 
			
		||||
    <string name="tile_disabled">Выключено</string>
 | 
			
		||||
    <string name="tile_enabled">Включено</string>
 | 
			
		||||
    <string name="tile_enabled">Включено (Нет подключения)</string>
 | 
			
		||||
    <string name="tile_connected">Подключено</string>
 | 
			
		||||
    <string name="location_amsterdam">Амстердам, Нидерланды</string>
 | 
			
		||||
    <string name="location_prague">Прага, Чехия</string>
 | 
			
		||||
    <string name="location_bratislava">Братислава, Словакия</string>
 | 
			
		||||
    <string name="location_buffalo">Баффало, США</string>
 | 
			
		||||
    <string name="channel_name">Сервис VPN</string>
 | 
			
		||||
    <string name="channel_description">Главный канал нотификаций сервиса</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			@ -22,8 +22,8 @@
 | 
			
		|||
    <string name="dns_one_server">1 server</string>
 | 
			
		||||
    <string name="dns_many_servers">%d server</string>
 | 
			
		||||
    <string name="dns_remove_title">Remove %s?</string>
 | 
			
		||||
    <string name="main_no_connectivity">No connectivity</string>
 | 
			
		||||
    <string name="main_enabled">Enabled</string>
 | 
			
		||||
    <string name="main_no_connectivity">Enabled (No connectivity)</string>
 | 
			
		||||
    <string name="main_enabled">Connected</string>
 | 
			
		||||
    <string name="main_disabled">Not enabled</string>
 | 
			
		||||
    <string name="main_no_peers">No peers</string>
 | 
			
		||||
    <string name="main_one_peer">1 peer</string>
 | 
			
		||||
| 
						 | 
				
			
			@ -66,10 +66,12 @@
 | 
			
		|||
    <string name="reset_configuration">Reset configuration</string>
 | 
			
		||||
    <string name="reset_configuration_hint">Resetting will overwrite with newly generated configuration. Your public keys and IP address on the network will change.</string>
 | 
			
		||||
    <string name="tile_disabled">Disabled</string>
 | 
			
		||||
    <string name="tile_enabled">Enabled</string>
 | 
			
		||||
    <string name="tile_enabled">Enabled (No connectivity)</string>
 | 
			
		||||
    <string name="tile_connected">Connected</string>
 | 
			
		||||
    <string name="location_amsterdam">Amsterdam, NL</string>
 | 
			
		||||
    <string name="location_prague">Prague, CZ</string>
 | 
			
		||||
    <string name="location_bratislava">Bratislava, SK</string>
 | 
			
		||||
    <string name="location_buffalo">Buffalo, US</string>
 | 
			
		||||
    <string name="channel_name">VPN Service</string>
 | 
			
		||||
    <string name="channel_description">Main channel for foreground notification</string>
 | 
			
		||||
</resources>
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue