Compare commits

...

10 Commits

Author SHA1 Message Date
Jeff d96e039cc0
fix for ci 2022-03-09 16:51:33 -05:00
Jeff a07171ea8c
Revert "fix for ci"
This reverts commit 9182d20578.
2022-03-09 16:51:32 -05:00
majestrate 2aa0d15555
Merge pull request #12 from frtget/fix-use-last-config-when-started-by-system
Use the latest values when started by the system (because the Always-on VPN setting is on)
2022-03-09 16:19:09 -05:00
frtget c3d2b32855 Use latest values when started by the system 2022-03-09 16:03:48 -05:00
Jeff d1348d9878
bump submodule 2022-03-09 15:43:29 -05:00
majestrate babfb69e64
Merge pull request #11 from frtget/fix-status-updates
minor status related changes
2022-03-09 15:40:05 -05:00
frtget 50c927a36d LokinetLib.info -> LokinetLib.status 2022-03-09 15:34:30 -05:00
frtget 6d7a9c54a3 Bind on start & fix onRevoke +NullPointerException 2022-03-09 15:28:04 -05:00
frtget 3af9e768ae Rename variables 2022-03-09 10:27:05 -05:00
frtget 04233c8f1a minor status related changes 2022-03-08 18:11:16 -05:00
7 changed files with 93 additions and 52 deletions

View File

@ -43,6 +43,7 @@ android {
targetSdkVersion 29
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
manifestPlaceholders += [applicationName: "android.app.Application"]
}
buildTypes {

View File

@ -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

View File

@ -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),
),
),

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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));
}
}