mirror of
				https://github.com/yggdrasil-network/yggdrasil-android.git
				synced 2025-11-03 18:55:08 +03:00 
			
		
		
		
	Fixes #30, added quick settings icon.
This commit is contained in:
		
							parent
							
								
									ee81f4e902
								
							
						
					
					
						commit
						1152070fac
					
				
					 9 changed files with 296 additions and 19 deletions
				
			
		| 
						 | 
					@ -13,10 +13,6 @@
 | 
				
			||||||
        android:roundIcon="@drawable/ic_launcher_round"
 | 
					        android:roundIcon="@drawable/ic_launcher_round"
 | 
				
			||||||
        android:supportsRtl="true"
 | 
					        android:supportsRtl="true"
 | 
				
			||||||
        android:theme="@style/Theme.Yggdrasil">
 | 
					        android:theme="@style/Theme.Yggdrasil">
 | 
				
			||||||
        <activity android:name=".SettingsActivity"
 | 
					 | 
				
			||||||
            android:parentActivityName=".MainActivity" />
 | 
					 | 
				
			||||||
        <activity android:name=".PeersActivity"
 | 
					 | 
				
			||||||
            android:parentActivityName=".MainActivity" />
 | 
					 | 
				
			||||||
        <activity android:name=".MainActivity" android:exported="true">
 | 
					        <activity android:name=".MainActivity" android:exported="true">
 | 
				
			||||||
            <intent-filter>
 | 
					            <intent-filter>
 | 
				
			||||||
                <action android:name="android.intent.action.MAIN" />
 | 
					                <action android:name="android.intent.action.MAIN" />
 | 
				
			||||||
| 
						 | 
					@ -24,7 +20,21 @@
 | 
				
			||||||
                <category android:name="android.intent.category.LAUNCHER" />
 | 
					                <category android:name="android.intent.category.LAUNCHER" />
 | 
				
			||||||
            </intent-filter>
 | 
					            </intent-filter>
 | 
				
			||||||
        </activity>
 | 
					        </activity>
 | 
				
			||||||
 | 
					        <activity android:name=".SettingsActivity" android:parentActivityName=".MainActivity" />
 | 
				
			||||||
 | 
					        <activity android:name=".PeersActivity" android:parentActivityName=".MainActivity" />
 | 
				
			||||||
        <activity android:name=".DnsActivity" android:exported="false" />
 | 
					        <activity android:name=".DnsActivity" android:exported="false" />
 | 
				
			||||||
 | 
					        <activity android:name=".TileServiceActivity" android:theme="@android:style/Theme.NoDisplay"
 | 
				
			||||||
 | 
					            android:allowTaskReparenting="true"
 | 
				
			||||||
 | 
					            android:alwaysRetainTaskState="false"
 | 
				
			||||||
 | 
					            android:clearTaskOnLaunch="true"
 | 
				
			||||||
 | 
					            android:enabled="true"
 | 
				
			||||||
 | 
					            android:exported="true"
 | 
				
			||||||
 | 
					            android:excludeFromRecents="true"
 | 
				
			||||||
 | 
					            android:finishOnTaskLaunch="true">
 | 
				
			||||||
 | 
					            <intent-filter>
 | 
				
			||||||
 | 
					                <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
 | 
				
			||||||
 | 
					            </intent-filter>
 | 
				
			||||||
 | 
					        </activity>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <service
 | 
					        <service
 | 
				
			||||||
            android:name=".PacketTunnelProvider"
 | 
					            android:name=".PacketTunnelProvider"
 | 
				
			||||||
| 
						 | 
					@ -34,6 +44,18 @@
 | 
				
			||||||
                <action android:name="android.net.VpnService" />
 | 
					                <action android:name="android.net.VpnService" />
 | 
				
			||||||
            </intent-filter>
 | 
					            </intent-filter>
 | 
				
			||||||
        </service>
 | 
					        </service>
 | 
				
			||||||
 | 
					        <service
 | 
				
			||||||
 | 
					            android:name=".YggTileService"
 | 
				
			||||||
 | 
					            android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
 | 
				
			||||||
 | 
					            android:icon="@drawable/ic_tile_icon"
 | 
				
			||||||
 | 
					            android:label="@string/app_name"
 | 
				
			||||||
 | 
					            android:exported="true">
 | 
				
			||||||
 | 
					            <meta-data android:name="android.service.quicksettings.ACTIVE_TILE" android:value="true" />
 | 
				
			||||||
 | 
					            <meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE" android:value="true" />
 | 
				
			||||||
 | 
					            <intent-filter>
 | 
				
			||||||
 | 
					                <action android:name="android.service.quicksettings.action.QS_TILE" />
 | 
				
			||||||
 | 
					            </intent-filter>
 | 
				
			||||||
 | 
					        </service>
 | 
				
			||||||
    </application>
 | 
					    </application>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</manifest>
 | 
					</manifest>
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,22 @@
 | 
				
			||||||
package eu.neilalexander.yggdrasil
 | 
					package eu.neilalexander.yggdrasil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.app.Application
 | 
					import android.app.Application
 | 
				
			||||||
 | 
					import android.content.ComponentName
 | 
				
			||||||
 | 
					import android.os.Build
 | 
				
			||||||
 | 
					import android.service.quicksettings.TileService
 | 
				
			||||||
 | 
					import androidx.annotation.RequiresApi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GlobalApplication: Application() {
 | 
					class GlobalApplication: Application(), YggStateReceiver.StateReceiver {
 | 
				
			||||||
    private lateinit var config: ConfigurationProxy
 | 
					    private lateinit var config: ConfigurationProxy
 | 
				
			||||||
 | 
					    private var currentState: State = State.Disabled
 | 
				
			||||||
    var updaterConnections: Int = 0
 | 
					    var updaterConnections: Int = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun onCreate() {
 | 
					    override fun onCreate() {
 | 
				
			||||||
        super.onCreate()
 | 
					        super.onCreate()
 | 
				
			||||||
        config = ConfigurationProxy(applicationContext)
 | 
					        config = ConfigurationProxy(applicationContext)
 | 
				
			||||||
        val callback = NetworkStateCallback(this)
 | 
					        val callback = NetworkStateCallback(this)
 | 
				
			||||||
 | 
					        val receiver = YggStateReceiver(this)
 | 
				
			||||||
 | 
					        receiver.register(this)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun subscribe() {
 | 
					    fun subscribe() {
 | 
				
			||||||
| 
						 | 
					@ -25,4 +32,17 @@ class GlobalApplication: Application() {
 | 
				
			||||||
    fun needUiUpdates(): Boolean {
 | 
					    fun needUiUpdates(): Boolean {
 | 
				
			||||||
        return updaterConnections > 0
 | 
					        return updaterConnections > 0
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun getCurrentState(): State {
 | 
				
			||||||
 | 
					        return currentState
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @RequiresApi(Build.VERSION_CODES.N)
 | 
				
			||||||
 | 
					    override fun onStateChange(state: State) {
 | 
				
			||||||
 | 
					        if (state != currentState) {
 | 
				
			||||||
 | 
					            val componentName = ComponentName(this, YggTileService::class.java)
 | 
				
			||||||
 | 
					            TileService.requestListeningState(this, componentName)
 | 
				
			||||||
 | 
					            currentState = state
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,9 @@ import android.os.ParcelFileDescriptor
 | 
				
			||||||
import android.system.OsConstants
 | 
					import android.system.OsConstants
 | 
				
			||||||
import android.util.Log
 | 
					import android.util.Log
 | 
				
			||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
 | 
					import androidx.localbroadcastmanager.content.LocalBroadcastManager
 | 
				
			||||||
 | 
					import eu.neilalexander.yggdrasil.YggStateReceiver.Companion.YGG_STATE_INTENT
 | 
				
			||||||
import mobile.Yggdrasil
 | 
					import mobile.Yggdrasil
 | 
				
			||||||
 | 
					import org.json.JSONArray
 | 
				
			||||||
import java.io.FileInputStream
 | 
					import java.io.FileInputStream
 | 
				
			||||||
import java.io.FileOutputStream
 | 
					import java.io.FileOutputStream
 | 
				
			||||||
import java.util.concurrent.atomic.AtomicBoolean
 | 
					import java.util.concurrent.atomic.AtomicBoolean
 | 
				
			||||||
| 
						 | 
					@ -21,6 +23,7 @@ class PacketTunnelProvider: VpnService() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const val ACTION_START = "eu.neilalexander.yggdrasil.PacketTunnelProvider.START"
 | 
					        const val ACTION_START = "eu.neilalexander.yggdrasil.PacketTunnelProvider.START"
 | 
				
			||||||
        const val ACTION_STOP = "eu.neilalexander.yggdrasil.PacketTunnelProvider.STOP"
 | 
					        const val ACTION_STOP = "eu.neilalexander.yggdrasil.PacketTunnelProvider.STOP"
 | 
				
			||||||
 | 
					        const val ACTION_TOGGLE = "eu.neilalexander.yggdrasil.PacketTunnelProvider.TOGGLE"
 | 
				
			||||||
        const val ACTION_CONNECT = "eu.neilalexander.yggdrasil.PacketTunnelProvider.CONNECT"
 | 
					        const val ACTION_CONNECT = "eu.neilalexander.yggdrasil.PacketTunnelProvider.CONNECT"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,7 +62,20 @@ class PacketTunnelProvider: VpnService() {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ACTION_CONNECT -> {
 | 
					            ACTION_CONNECT -> {
 | 
				
			||||||
                Log.d(TAG, "Connecting...")
 | 
					                Log.d(TAG, "Connecting...")
 | 
				
			||||||
                connect(); START_STICKY
 | 
					                if (started.get()) {
 | 
				
			||||||
 | 
					                    connect();
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    start();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                START_STICKY
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ACTION_TOGGLE -> {
 | 
				
			||||||
 | 
					                Log.d(TAG, "Toggling...")
 | 
				
			||||||
 | 
					                if (started.get()) {
 | 
				
			||||||
 | 
					                    stop(); START_NOT_STICKY
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    start(); START_STICKY
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else -> {
 | 
					            else -> {
 | 
				
			||||||
                Log.d(TAG, "Starting...")
 | 
					                Log.d(TAG, "Starting...")
 | 
				
			||||||
| 
						 | 
					@ -135,7 +151,7 @@ class PacketTunnelProvider: VpnService() {
 | 
				
			||||||
            updater()
 | 
					            updater()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val intent = Intent(STATE_INTENT)
 | 
					        var intent = Intent(STATE_INTENT)
 | 
				
			||||||
        intent.putExtra("type", "state")
 | 
					        intent.putExtra("type", "state")
 | 
				
			||||||
        intent.putExtra("started", true)
 | 
					        intent.putExtra("started", true)
 | 
				
			||||||
        intent.putExtra("ip", yggdrasil.addressString)
 | 
					        intent.putExtra("ip", yggdrasil.addressString)
 | 
				
			||||||
| 
						 | 
					@ -143,6 +159,10 @@ class PacketTunnelProvider: VpnService() {
 | 
				
			||||||
        intent.putExtra("coords", yggdrasil.coordsString)
 | 
					        intent.putExtra("coords", yggdrasil.coordsString)
 | 
				
			||||||
        intent.putExtra("peers", yggdrasil.peersJSON)
 | 
					        intent.putExtra("peers", yggdrasil.peersJSON)
 | 
				
			||||||
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
 | 
					        LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        intent = Intent(YGG_STATE_INTENT)
 | 
				
			||||||
 | 
					        intent.putExtra("state", STATE_ENABLED)
 | 
				
			||||||
 | 
					        LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun stop() {
 | 
					    private fun stop() {
 | 
				
			||||||
| 
						 | 
					@ -178,11 +198,15 @@ class PacketTunnelProvider: VpnService() {
 | 
				
			||||||
            updateThread = null
 | 
					            updateThread = null
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val intent = Intent(STATE_INTENT)
 | 
					        var intent = Intent(STATE_INTENT)
 | 
				
			||||||
        intent.putExtra("type", "state")
 | 
					        intent.putExtra("type", "state")
 | 
				
			||||||
        intent.putExtra("started", false)
 | 
					        intent.putExtra("started", false)
 | 
				
			||||||
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
 | 
					        LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        intent = Intent(YGG_STATE_INTENT)
 | 
				
			||||||
 | 
					        intent.putExtra("state", STATE_DISABLED)
 | 
				
			||||||
 | 
					        LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        stopSelf()
 | 
					        stopSelf()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,6 +218,7 @@ class PacketTunnelProvider: VpnService() {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun updater() {
 | 
					    private fun updater() {
 | 
				
			||||||
 | 
					        var lastStateUpdate = System.currentTimeMillis()
 | 
				
			||||||
        updates@ while (started.get()) {
 | 
					        updates@ while (started.get()) {
 | 
				
			||||||
            if ((application as  GlobalApplication).needUiUpdates()) {
 | 
					            if ((application as  GlobalApplication).needUiUpdates()) {
 | 
				
			||||||
                val intent = Intent(STATE_INTENT)
 | 
					                val intent = Intent(STATE_INTENT)
 | 
				
			||||||
| 
						 | 
					@ -205,24 +230,37 @@ class PacketTunnelProvider: VpnService() {
 | 
				
			||||||
                intent.putExtra("peers", yggdrasil.peersJSON)
 | 
					                intent.putExtra("peers", yggdrasil.peersJSON)
 | 
				
			||||||
                intent.putExtra("dht", yggdrasil.dhtjson)
 | 
					                intent.putExtra("dht", yggdrasil.dhtjson)
 | 
				
			||||||
                LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
 | 
					                LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                try {
 | 
					 | 
				
			||||||
                    Thread.sleep(1000)
 | 
					 | 
				
			||||||
                } catch (e: InterruptedException) {
 | 
					 | 
				
			||||||
                    return
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            val curTime = System.currentTimeMillis()
 | 
				
			||||||
 | 
					            if (lastStateUpdate + 10000 < curTime) {
 | 
				
			||||||
 | 
					                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
 | 
				
			||||||
 | 
					                intent.putExtra("state", state)
 | 
				
			||||||
 | 
					                LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
 | 
				
			||||||
 | 
					                lastStateUpdate = curTime
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (Thread.currentThread().isInterrupted) {
 | 
					            if (Thread.currentThread().isInterrupted) {
 | 
				
			||||||
                break@updates
 | 
					                break@updates
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            try {
 | 
					            if (sleep()) return
 | 
				
			||||||
                Thread.sleep(1000)
 | 
					 | 
				
			||||||
            } catch (e: InterruptedException) {
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun sleep(): Boolean {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Thread.sleep(1000)
 | 
				
			||||||
 | 
					        } catch (e: InterruptedException) {
 | 
				
			||||||
 | 
					            return true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun writer() {
 | 
					    private fun writer() {
 | 
				
			||||||
        val buf = ByteArray(65535)
 | 
					        val buf = ByteArray(65535)
 | 
				
			||||||
        writes@ while (started.get()) {
 | 
					        writes@ while (started.get()) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					package eu.neilalexander.yggdrasil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.app.Activity
 | 
				
			||||||
 | 
					import android.content.Intent
 | 
				
			||||||
 | 
					import android.os.Bundle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TileServiceActivity : Activity() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onCreate(savedInstanceState: Bundle?) {
 | 
				
			||||||
 | 
					        super.onCreate(savedInstanceState)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Just starting MainActivity
 | 
				
			||||||
 | 
					        val intent = Intent(this, MainActivity::class.java)
 | 
				
			||||||
 | 
					        startService(intent)
 | 
				
			||||||
 | 
					        finish()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,53 @@
 | 
				
			||||||
 | 
					package eu.neilalexander.yggdrasil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.content.BroadcastReceiver
 | 
				
			||||||
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import android.content.Intent
 | 
				
			||||||
 | 
					import android.content.IntentFilter
 | 
				
			||||||
 | 
					import androidx.localbroadcastmanager.content.LocalBroadcastManager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const val STATE_ENABLED = "enabled"
 | 
				
			||||||
 | 
					const val STATE_DISABLED = "disabled"
 | 
				
			||||||
 | 
					const val STATE_CONNECTED = "connected"
 | 
				
			||||||
 | 
					const val STATE_RECONNECTING = "reconnecting"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class YggStateReceiver(var receiver: StateReceiver): BroadcastReceiver() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    companion object {
 | 
				
			||||||
 | 
					        const val YGG_STATE_INTENT = "eu.neilalexander.yggdrasil.YggStateReceiver.STATE"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onReceive(context: Context?, intent: Intent?) {
 | 
				
			||||||
 | 
					        if (context == null) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val state = when (intent?.getStringExtra("state")) {
 | 
				
			||||||
 | 
					            STATE_ENABLED -> State.Enabled
 | 
				
			||||||
 | 
					            STATE_DISABLED -> State.Disabled
 | 
				
			||||||
 | 
					            STATE_CONNECTED -> State.Connected
 | 
				
			||||||
 | 
					            STATE_RECONNECTING -> State.Reconnecting
 | 
				
			||||||
 | 
					            else -> State.Unknown
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        receiver.onStateChange(state)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun register(context: Context) {
 | 
				
			||||||
 | 
					        LocalBroadcastManager.getInstance(context).registerReceiver(
 | 
				
			||||||
 | 
					            this, IntentFilter(YGG_STATE_INTENT)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun unregister(context: Context) {
 | 
				
			||||||
 | 
					        LocalBroadcastManager.getInstance(context).unregisterReceiver(this)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    interface StateReceiver {
 | 
				
			||||||
 | 
					        fun onStateChange(state: State)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A class-supporter with an Yggdrasil state
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum class State {
 | 
				
			||||||
 | 
					    Unknown, Disabled, Enabled, Connected, Reconnecting;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										107
									
								
								app/src/main/java/eu/neilalexander/yggdrasil/YggTileService.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								app/src/main/java/eu/neilalexander/yggdrasil/YggTileService.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,107 @@
 | 
				
			||||||
 | 
					package eu.neilalexander.yggdrasil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.content.Intent
 | 
				
			||||||
 | 
					import android.graphics.drawable.Icon
 | 
				
			||||||
 | 
					import android.os.Build
 | 
				
			||||||
 | 
					import android.os.IBinder
 | 
				
			||||||
 | 
					import android.service.quicksettings.Tile
 | 
				
			||||||
 | 
					import android.service.quicksettings.TileService
 | 
				
			||||||
 | 
					import android.util.Log
 | 
				
			||||||
 | 
					import androidx.annotation.RequiresApi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private const val TAG = "TileService"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@RequiresApi(Build.VERSION_CODES.N)
 | 
				
			||||||
 | 
					class YggTileService: TileService(), YggStateReceiver.StateReceiver {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private lateinit var receiver: YggStateReceiver
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onCreate() {
 | 
				
			||||||
 | 
					        super.onCreate()
 | 
				
			||||||
 | 
					        receiver = YggStateReceiver(this)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * We need to override the method onBind to avoid crashes that were detected on Android 8
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * The possible reason of crashes is described here:
 | 
				
			||||||
 | 
					     * https://github.com/aosp-mirror/platform_frameworks_base/commit/ee68fd889c2dfcd895b8e73fc39d7b97826dc3d8
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    override fun onBind(intent: Intent?): IBinder? {
 | 
				
			||||||
 | 
					        return try {
 | 
				
			||||||
 | 
					            super.onBind(intent)
 | 
				
			||||||
 | 
					        } catch (th: Throwable) {
 | 
				
			||||||
 | 
					            null
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onTileAdded() {
 | 
				
			||||||
 | 
					        super.onTileAdded()
 | 
				
			||||||
 | 
					        updateTileState((application as GlobalApplication).getCurrentState())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onTileRemoved() {
 | 
				
			||||||
 | 
					        super.onTileRemoved()
 | 
				
			||||||
 | 
					        updateTileState((application as GlobalApplication).getCurrentState())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onStartListening() {
 | 
				
			||||||
 | 
					        super.onStartListening()
 | 
				
			||||||
 | 
					        receiver.register(this)
 | 
				
			||||||
 | 
					        updateTileState((application as GlobalApplication).getCurrentState())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onStopListening() {
 | 
				
			||||||
 | 
					        super.onStopListening()
 | 
				
			||||||
 | 
					        receiver.unregister(this)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onDestroy() {
 | 
				
			||||||
 | 
					        super.onDestroy()
 | 
				
			||||||
 | 
					        receiver.unregister(this)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onClick() {
 | 
				
			||||||
 | 
					        super.onClick()
 | 
				
			||||||
 | 
					        val intent = Intent(this, PacketTunnelProvider::class.java)
 | 
				
			||||||
 | 
					        intent.action = PacketTunnelProvider.ACTION_TOGGLE
 | 
				
			||||||
 | 
					        startService(intent)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        var changed = oldState != tile.state
 | 
				
			||||||
 | 
					        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
 | 
				
			||||||
 | 
					            val oldText = tile.subtitle
 | 
				
			||||||
 | 
					            tile.subtitle = when (state) {
 | 
				
			||||||
 | 
					                State.Enabled -> getText(R.string.tile_enabled)
 | 
				
			||||||
 | 
					                State.Connected -> getText(R.string.tile_connected)
 | 
				
			||||||
 | 
					                else -> getText(R.string.tile_disabled)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            changed = changed || (oldText != tile.subtitle)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Update tile if changed state
 | 
				
			||||||
 | 
					        if (changed) {
 | 
				
			||||||
 | 
					            Log.i(TAG, "Updating tile, old state: $oldState, new state: ${tile.state}")
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					              Force set the icon in the tile, because there is a problem on icon tint in the Android Oreo.
 | 
				
			||||||
 | 
					              Issue: https://github.com/AdguardTeam/AdguardForAndroid/issues/1996
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            tile.icon = Icon.createWithResource(applicationContext, R.drawable.ic_tile_icon)
 | 
				
			||||||
 | 
					            tile.updateTile()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onStateChange(state: State) {
 | 
				
			||||||
 | 
					        updateTileState(state)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										14
									
								
								app/src/main/res/drawable/ic_tile_icon.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/src/main/res/drawable/ic_tile_icon.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
 | 
					    android:width="480dp"
 | 
				
			||||||
 | 
					    android:height="480dp"
 | 
				
			||||||
 | 
					    android:viewportWidth="480"
 | 
				
			||||||
 | 
					    android:viewportHeight="480">
 | 
				
			||||||
 | 
					  <path
 | 
				
			||||||
 | 
					      android:pathData="m58.51,474.95c1.37,-5.62 17.69,-45.43 32.05,-78.2c14.7,-33.54 14.42,-32.23 10.32,-49.01c-5.11,-20.95 -4.8,-55.06 0.67,-73.17c19.73,-65.38 70.97,-109.69 182.24,-157.59c36.24,-15.6 56.14,-25.61 71.24,-35.83c26.61,-18.01 54.3,-49.27 63.15,-71.29c1.87,-4.65 3.96,-8.4 4.66,-8.35c2.18,0.16 1.1,66.01 -1.46,88.95c-15.82,142.09 -64.01,234.52 -143.35,274.93c-45.79,23.32 -117.97,31.97 -151.59,18.15c-4.75,-1.95 -9.76,-3.55 -11.12,-3.55c-5.12,0 -23.48,49.02 -28.75,76.76c-1.64,8.61 -4.12,20.42 -4.48,22.23c-8.2,-0.06 -0.53,-0.02 -12.19,-0.02l-12.36,0z"
 | 
				
			||||||
 | 
					      android:strokeLineJoin="miter"
 | 
				
			||||||
 | 
					      android:strokeWidth="1.49"
 | 
				
			||||||
 | 
					      android:fillColor="#FFFFFF"
 | 
				
			||||||
 | 
					      android:fillType="nonZero"
 | 
				
			||||||
 | 
					      android:strokeColor="#00000000"
 | 
				
			||||||
 | 
					      android:strokeLineCap="butt"/>
 | 
				
			||||||
 | 
					</vector>
 | 
				
			||||||
| 
						 | 
					@ -65,6 +65,9 @@
 | 
				
			||||||
    <string name="public_key_hint">Ваш публичный ключ идентифицирует вас в сети. Его распространение безопасно.</string>
 | 
					    <string name="public_key_hint">Ваш публичный ключ идентифицирует вас в сети. Его распространение безопасно.</string>
 | 
				
			||||||
    <string name="reset_configuration">Сбросить настройки</string>
 | 
					    <string name="reset_configuration">Сбросить настройки</string>
 | 
				
			||||||
    <string name="reset_configuration_hint">Сброс создаст полностью новые настройки. Это изменит ваш публичный ключ и адрес IP.</string>
 | 
					    <string name="reset_configuration_hint">Сброс создаст полностью новые настройки. Это изменит ваш публичный ключ и адрес IP.</string>
 | 
				
			||||||
 | 
					    <string name="tile_disabled">Выключено</string>
 | 
				
			||||||
 | 
					    <string name="tile_enabled">Включено</string>
 | 
				
			||||||
 | 
					    <string name="tile_connected">Подключено</string>
 | 
				
			||||||
    <string name="location_amsterdam">Амстердам, Нидерланды</string>
 | 
					    <string name="location_amsterdam">Амстердам, Нидерланды</string>
 | 
				
			||||||
    <string name="location_prague">Прага, Чехия</string>
 | 
					    <string name="location_prague">Прага, Чехия</string>
 | 
				
			||||||
    <string name="location_bratislava">Братислава, Словакия</string>
 | 
					    <string name="location_bratislava">Братислава, Словакия</string>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,6 +65,9 @@
 | 
				
			||||||
    <string name="public_key_hint">Your public key forms your identity on the network. It is safe to be shared.</string>
 | 
					    <string name="public_key_hint">Your public key forms your identity on the network. It is safe to be shared.</string>
 | 
				
			||||||
    <string name="reset_configuration">Reset configuration</string>
 | 
					    <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="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_connected">Connected</string>
 | 
				
			||||||
    <string name="location_amsterdam">Amsterdam, NL</string>
 | 
					    <string name="location_amsterdam">Amsterdam, NL</string>
 | 
				
			||||||
    <string name="location_prague">Prague, CZ</string>
 | 
					    <string name="location_prague">Prague, CZ</string>
 | 
				
			||||||
    <string name="location_bratislava">Bratislava, SK</string>
 | 
					    <string name="location_bratislava">Bratislava, SK</string>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue