Compare commits
10 Commits
9182d20578
...
d96e039cc0
Author | SHA1 | Date |
---|---|---|
Jeff | d96e039cc0 | |
Jeff | a07171ea8c | |
majestrate | 2aa0d15555 | |
frtget | c3d2b32855 | |
Jeff | d1348d9878 | |
majestrate | babfb69e64 | |
frtget | 50c927a36d | |
frtget | 6d7a9c54a3 | |
frtget | 3af9e768ae | |
frtget | 04233c8f1a |
|
@ -43,6 +43,7 @@ android {
|
|||
targetSdkVersion 29
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
manifestPlaceholders += [applicationName: "android.app.Application"]
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<application
|
||||
android:name="android.app.Application"
|
||||
android:name="${applicationName}"
|
||||
android:label="Lokinet"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
|
|
|
@ -87,28 +87,26 @@ class MyForm extends StatefulWidget {
|
|||
|
||||
class MyFormState extends State<MyForm> {
|
||||
static final key = new GlobalKey<FormState>();
|
||||
bool isConnected = false;
|
||||
StreamSubscription<bool> _isConnectedEventSubscription;
|
||||
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
LokinetLib.onStatusUpdate((bool status) => setState(() {
|
||||
isConnected = status;
|
||||
}));
|
||||
_isConnectedEventSubscription = LokinetLib.isConnectedEventStream
|
||||
.listen((bool isConnected) => setState(() {}));
|
||||
}
|
||||
|
||||
Future _updateLokinetStatus() async {
|
||||
var _isConnected = await LokinetLib.isRunning;
|
||||
setState(() {
|
||||
isConnected = _isConnected;
|
||||
});
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
_isConnectedEventSubscription?.cancel();
|
||||
}
|
||||
|
||||
Future toggleLokinet() async {
|
||||
if (!key.currentState.validate()) {
|
||||
return;
|
||||
}
|
||||
if (await LokinetLib.isRunning) {
|
||||
if (LokinetLib.isConnected) {
|
||||
await LokinetLib.disconnectFromLokinet();
|
||||
} else {
|
||||
//Save the exit node and upstream dns
|
||||
|
@ -187,7 +185,7 @@ class MyFormState extends State<MyForm> {
|
|||
Padding(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: Text(
|
||||
isConnected ? "Connected" : "Not Connected",
|
||||
LokinetLib.isConnected ? "Connected" : "Not Connected",
|
||||
style: TextStyle(color: color),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package network.loki.lokinet;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.net.VpnService;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
|
@ -53,22 +55,22 @@ public class LokinetDaemon extends VpnService {
|
|||
int m_FD = -1;
|
||||
int m_UDPSocket = -1;
|
||||
|
||||
private Timer mStatusCheckTimer;
|
||||
private MutableLiveData<Boolean> mStatus = new MutableLiveData<Boolean>();
|
||||
private Timer mUpdateIsConnectedTimer;
|
||||
private MutableLiveData<Boolean> isConnected = new MutableLiveData<Boolean>();
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
mStatus.postValue(false);
|
||||
mStatusCheckTimer = new Timer();
|
||||
mStatusCheckTimer.schedule(new CheckStatus(), 0, 500);
|
||||
isConnected.postValue(false);
|
||||
mUpdateIsConnectedTimer = new Timer();
|
||||
mUpdateIsConnectedTimer.schedule(new UpdateIsConnectedTask(), 0, 500);
|
||||
super.onCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (mStatusCheckTimer != null) {
|
||||
mStatusCheckTimer.cancel();
|
||||
mStatusCheckTimer = null;
|
||||
if (mUpdateIsConnectedTimer != null) {
|
||||
mUpdateIsConnectedTimer.cancel();
|
||||
mUpdateIsConnectedTimer = null;
|
||||
}
|
||||
|
||||
super.onDestroy();
|
||||
|
@ -79,12 +81,32 @@ public class LokinetDaemon extends VpnService {
|
|||
public int onStartCommand(Intent intent, int flags, int startID) {
|
||||
Log.d(LOG_TAG, "onStartCommand()");
|
||||
|
||||
if (intent.getAction().equals(ACTION_DISCONNECT)) {
|
||||
String action = intent != null ? intent.getAction() : "";
|
||||
|
||||
if (ACTION_DISCONNECT.equals(action)) {
|
||||
disconnect();
|
||||
return START_NOT_STICKY;
|
||||
} else {
|
||||
ArrayList<ConfigValue> configVals = new ArrayList<ConfigValue>();
|
||||
String exitNode = intent.getStringExtra(EXIT_NODE);
|
||||
|
||||
String exitNode = null;
|
||||
String upstreamDNS = null;
|
||||
|
||||
SharedPreferences sharedPreferences = getSharedPreferences("lokinet_lib", MODE_PRIVATE);
|
||||
|
||||
if (ACTION_CONNECT.equals(action)) { // started by the app
|
||||
exitNode = intent.getStringExtra(EXIT_NODE);
|
||||
upstreamDNS = intent.getStringExtra(UPSTREAM_DNS);
|
||||
// save values
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putString(EXIT_NODE, exitNode);
|
||||
editor.putString(UPSTREAM_DNS, upstreamDNS);
|
||||
editor.commit();
|
||||
} else { // if started by the system because Always-on VPN setting is enabled
|
||||
// use the latest values
|
||||
exitNode = sharedPreferences.getString(EXIT_NODE, null);
|
||||
upstreamDNS = sharedPreferences.getString(UPSTREAM_DNS, null);
|
||||
}
|
||||
|
||||
if (exitNode == null || exitNode.isEmpty()) {
|
||||
exitNode = DEFAULT_EXIT_NODE;
|
||||
|
@ -94,8 +116,6 @@ public class LokinetDaemon extends VpnService {
|
|||
Log.e(LOG_TAG, "Using " + exitNode + " as exit-node.");
|
||||
configVals.add(new ConfigValue("network", "exit-node", exitNode));
|
||||
|
||||
String upstreamDNS = intent.getStringExtra(UPSTREAM_DNS);
|
||||
|
||||
if (upstreamDNS == null || upstreamDNS.isEmpty()) {
|
||||
upstreamDNS = DEFAULT_UPSTREAM_DNS;
|
||||
Log.e(LOG_TAG, "No upstream DNS configured! Proceeding with default.");
|
||||
|
@ -117,7 +137,8 @@ public class LokinetDaemon extends VpnService {
|
|||
|
||||
@Override
|
||||
public void onRevoke() {
|
||||
mStatus.postValue(false);
|
||||
Log.d(LOG_TAG, "onRevoke()");
|
||||
disconnect();
|
||||
super.onRevoke();
|
||||
}
|
||||
|
||||
|
@ -229,7 +250,7 @@ public class LokinetDaemon extends VpnService {
|
|||
} else {
|
||||
Log.d(LOG_TAG, "already running");
|
||||
}
|
||||
updateStatus();
|
||||
updateIsConnected();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -241,15 +262,15 @@ public class LokinetDaemon extends VpnService {
|
|||
// Free(impl);
|
||||
// impl = null;
|
||||
// }
|
||||
updateStatus();
|
||||
updateIsConnected();
|
||||
}
|
||||
|
||||
public MutableLiveData<Boolean> getStatus() {
|
||||
return mStatus;
|
||||
public MutableLiveData<Boolean> isConnected() {
|
||||
return isConnected;
|
||||
}
|
||||
|
||||
private void updateStatus() {
|
||||
mStatus.postValue(IsRunning() && VpnService.prepare(LokinetDaemon.this) == null);
|
||||
private void updateIsConnected() {
|
||||
isConnected.postValue(IsRunning() && VpnService.prepare(LokinetDaemon.this) == null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -264,14 +285,20 @@ public class LokinetDaemon extends VpnService {
|
|||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
String action = intent != null ? intent.getAction() : "";
|
||||
|
||||
if (VpnService.SERVICE_INTERFACE.equals(action)) {
|
||||
return super.onBind(intent);
|
||||
}
|
||||
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
|
||||
private class CheckStatus extends TimerTask {
|
||||
private class UpdateIsConnectedTask extends TimerTask {
|
||||
public void run() {
|
||||
updateStatus();
|
||||
updateIsConnected();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,10 +9,13 @@ import android.net.VpnService
|
|||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import androidx.annotation.NonNull
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.Observer
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||
import io.flutter.embedding.engine.plugins.lifecycle.HiddenLifecycleReference
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
|
@ -32,13 +35,20 @@ class LokinetLibPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
|
|||
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
|
||||
/// when the Flutter Engine is detached from the Activity
|
||||
private lateinit var mMethodChannel: MethodChannel
|
||||
private lateinit var mStatusEventChannel: EventChannel
|
||||
private lateinit var mIsConnectedEventChannel: EventChannel
|
||||
private var mEventSink: EventChannel.EventSink? = null
|
||||
|
||||
private var mStatusObserver =
|
||||
Observer<Boolean> { newStatus ->
|
||||
private var mIsConnectedObserver =
|
||||
Observer<Boolean> { newIsConnected ->
|
||||
// Propagate to the dart package.
|
||||
mEventSink?.success(newStatus)
|
||||
mEventSink?.success(newIsConnected)
|
||||
}
|
||||
|
||||
private var mLifecycleOwner =
|
||||
object : LifecycleOwner {
|
||||
override fun getLifecycle(): Lifecycle {
|
||||
return (activityBinding.lifecycle as HiddenLifecycleReference).lifecycle
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttachedToEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
|
@ -47,9 +57,9 @@ class LokinetLibPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
|
|||
mMethodChannel = MethodChannel(binding.binaryMessenger, "lokinet_lib_method_channel")
|
||||
mMethodChannel.setMethodCallHandler(this)
|
||||
|
||||
mStatusEventChannel =
|
||||
EventChannel(binding.binaryMessenger, "lokinet_lib_status_event_channel")
|
||||
mStatusEventChannel.setStreamHandler(
|
||||
mIsConnectedEventChannel =
|
||||
EventChannel(binding.binaryMessenger, "lokinet_lib_is_connected_event_channel")
|
||||
mIsConnectedEventChannel.setStreamHandler(
|
||||
object : EventChannel.StreamHandler {
|
||||
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
|
||||
mEventSink = events
|
||||
|
@ -153,12 +163,14 @@ class LokinetLibPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
|
|||
|
||||
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
|
||||
activityBinding = binding
|
||||
doBindService()
|
||||
}
|
||||
|
||||
override fun onDetachedFromActivity() {}
|
||||
|
||||
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
|
||||
activityBinding = binding
|
||||
doBindService()
|
||||
}
|
||||
|
||||
override fun onDetachedFromActivityForConfigChanges() {}
|
||||
|
@ -168,12 +180,10 @@ class LokinetLibPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
|
|||
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
||||
mBoundService = (service as LokinetDaemon.LocalBinder).getService()
|
||||
|
||||
mBoundService?.getStatus()?.observeForever(mStatusObserver)
|
||||
mBoundService?.isConnected()?.observe(mLifecycleOwner, mIsConnectedObserver)
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(className: ComponentName) {
|
||||
mBoundService?.getStatus()?.removeObserver(mStatusObserver)
|
||||
|
||||
mBoundService = null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 36925d0576af834d4d2380b80dee24e1353f9436
|
||||
Subproject commit 27d883157d4cb319a32e705168345e2a8ca9f32b
|
|
@ -9,8 +9,19 @@ class LokinetLib {
|
|||
static const MethodChannel _methodChannel =
|
||||
const MethodChannel('lokinet_lib_method_channel');
|
||||
|
||||
static const EventChannel _statusEventChannel =
|
||||
const EventChannel('lokinet_lib_status_event_channel');
|
||||
static const EventChannel _isConnectedEventChannel =
|
||||
const EventChannel('lokinet_lib_is_connected_event_channel');
|
||||
|
||||
static bool _isConnected = false;
|
||||
|
||||
static bool get isConnected => _isConnected;
|
||||
|
||||
static Stream<bool> _isConnectedEventStream = _isConnectedEventChannel
|
||||
.receiveBroadcastStream()
|
||||
.cast<bool>()
|
||||
..listen((dynamic newIsConnected) => _isConnected = newIsConnected);
|
||||
|
||||
static Stream<bool> get isConnectedEventStream => _isConnectedEventStream;
|
||||
|
||||
static Future bootstrapLokinet() async {
|
||||
final request = await HttpClient()
|
||||
|
@ -65,10 +76,4 @@ class LokinetLib {
|
|||
if (status.isNotEmpty) return jsonDecode(status);
|
||||
return null;
|
||||
}
|
||||
|
||||
static void onStatusUpdate(void Function(bool) onStatusUpdateCallback) {
|
||||
_statusEventChannel
|
||||
.receiveBroadcastStream()
|
||||
.listen((dynamic status) => onStatusUpdateCallback(status));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue