summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Schwabe <arne@rfc2549.org>2013-05-25 11:49:49 +0200
committerArne Schwabe <arne@rfc2549.org>2013-05-25 11:49:49 +0200
commitfa4b5e8c373ff19d8cc96f5bb7f636598ff279cd (patch)
tree359f5e2869990bc059c02efadb89d0997f0d3a5b
parent2fe7a0433ca5b7fc99a074639376714393091682 (diff)
Implement Option to pause VPN when screen is off (closes issue #162)
--HG-- rename : src/de/blinkt/openvpn/core/NetworkStateReceiver.java => src/de/blinkt/openvpn/core/DeviceStateReceiver.java
-rwxr-xr-xres/values/strings.xml4
-rw-r--r--res/xml/general_settings.xml17
-rw-r--r--src/de/blinkt/openvpn/core/DeviceStateReceiver.java202
-rw-r--r--src/de/blinkt/openvpn/core/NetworkStateReceiver.java90
-rw-r--r--src/de/blinkt/openvpn/core/OpenVpnService.java34
5 files changed, 235 insertions, 112 deletions
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 56dde3a8..de9bbcb3 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -278,5 +278,9 @@
<string name="no_external_app_allowed">No app allowed to use external API</string>
<string name="allowed_apps">Allowed apps: %s</string>
<string name="clearappsdialog">Clear list of allowed external apps?\nCurrent list of allowed apps:\n\n%s</string>
+ <string name="screenoff_summary">"Pause VPN when screen is off and less than 64 kB transferred data in 60s."</string>
+ <string name="screenoff_title">Pause VPN connection after screen off</string>
+ <string name="screenoff_pause">Pausing connection in screen off state: less than %1$s in %2$ss</string>
+ <string name="screen_nopersistenttun">ERROR: Persistent tun not enabled for this VPN. Ignoring option to pause VPN when screen is off</string>
</resources> \ No newline at end of file
diff --git a/res/xml/general_settings.xml b/res/xml/general_settings.xml
index 6dbf58bf..9aa62956 100644
--- a/res/xml/general_settings.xml
+++ b/res/xml/general_settings.xml
@@ -11,13 +11,6 @@
android:key="showlogwindow"
android:summary="@string/show_log_summary"
android:title="@string/show_log_window" />
- <!--
- <CheckBoxPreference
- android:defaultValue="false"
- android:key="statusafterconnect"
- android:summary="@string/keppstatus_summary"
- android:title="@string/keepstatus" />
- -->
<CheckBoxPreference
android:defaultValue="true"
android:key="usesystemproxy"
@@ -28,11 +21,17 @@
android:key="restartvpnonboot"
android:summary="@string/onbootrestartsummary"
android:title="@string/onbootrestart" />
+
+ <CheckBoxPreference
+ android:defaultValue="false"
+ android:key="screenoff"
+ android:summary="@string/screenoff_summary"
+ android:title="@string/screenoff_title" />
<Preference
android:key="clearapi"
- android:title="Clear allowed external apps"
- android:persistent="false" />
+ android:persistent="false"
+ android:title="Clear allowed external apps" />
<PreferenceCategory android:title="Device specifics Hacks" >
<CheckBoxPreference
diff --git a/src/de/blinkt/openvpn/core/DeviceStateReceiver.java b/src/de/blinkt/openvpn/core/DeviceStateReceiver.java
new file mode 100644
index 00000000..11096f48
--- /dev/null
+++ b/src/de/blinkt/openvpn/core/DeviceStateReceiver.java
@@ -0,0 +1,202 @@
+package de.blinkt.openvpn.core;
+
+import java.util.LinkedList;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.State;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import de.blinkt.openvpn.R;
+import de.blinkt.openvpn.core.OpenVPN.ByteCountListener;
+
+public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountListener {
+ private int lastNetwork=-1;
+ private OpenVPNMangement mManangement;
+
+ // Window time in s
+ private final int TRAFFIC_WINDOW = 60;
+ // Data traffic limit in bytes
+ private final long TRAFFIC_LIMIT = 64 * 1024;
+
+
+ connectState network= connectState.DISCONNECTED;
+ connectState screen = connectState.SHOULDBECONNECTED;
+
+ private String lastStateMsg=null;
+
+ enum connectState {
+ SHOULDBECONNECTED,
+ PENDINGDISCONNECT,
+ DISCONNECTED
+ }
+
+ static class Datapoint {
+ private Datapoint(long t, long d)
+ {
+ timestamp = t;
+ data = d;
+ }
+
+ long timestamp;
+ long data;
+ }
+
+ LinkedList<Datapoint> trafficdata = new LinkedList<DeviceStateReceiver.Datapoint>();
+
+ @Override
+ public void updateByteCount(long in, long out, long diffin, long diffout) {
+ Log.i("OpenVPN", String.format("State: %s %s",network.name(), screen.name()));
+
+ if (screen!=connectState.PENDINGDISCONNECT)
+ return;
+
+ long total = diffin + diffout;
+ trafficdata.add(new Datapoint(System.currentTimeMillis(),total));
+
+ while(trafficdata.getFirst().timestamp <= (System.currentTimeMillis() - TRAFFIC_WINDOW*1000)) {
+ trafficdata.removeFirst();
+ }
+
+ long windowtraffic = 0;
+ for (Datapoint dp: trafficdata)
+ windowtraffic += dp.data;
+
+ if(windowtraffic < TRAFFIC_LIMIT) {
+ screen = connectState.DISCONNECTED;
+ OpenVPN.logInfo(R.string.screenoff_pause,
+ OpenVpnService.humanReadableByteCount(TRAFFIC_LIMIT, false), TRAFFIC_WINDOW);
+ mManangement.pause();
+ }
+ Log.i("OpenVPN", String.format("State: %s %s total %d last %d time %d",network.name(), screen.name(),windowtraffic/1024,
+ total,
+ System.currentTimeMillis()/1024));
+
+ }
+
+
+
+ public DeviceStateReceiver(OpenVPNMangement magnagement) {
+ super();
+ mManangement = magnagement;
+ }
+
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+
+
+ if(ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+ networkStateChange(context);
+ } else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
+ boolean screenoff = prefs.getBoolean("screenoff", false);
+
+ if(screenoff && ! ProfileManager.getLastConnectedVpn().mPersistTun) {
+ OpenVPN.logError(R.string.screen_nopersistenttun);
+ } else if(screenoff) {
+ screen = connectState.PENDINGDISCONNECT;
+ fillTrafficData();
+ if (network == connectState.DISCONNECTED)
+ screen = connectState.DISCONNECTED;
+ }
+
+ } else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
+ // Network was disabled because screen off
+ if (screen == connectState.DISCONNECTED && network == connectState.SHOULDBECONNECTED) {
+ mManangement.resume();
+
+ }
+ screen = connectState.SHOULDBECONNECTED;
+
+ }
+ }
+
+ private void fillTrafficData() {
+ trafficdata.add(new Datapoint(System.currentTimeMillis(), TRAFFIC_LIMIT));
+ }
+
+
+ public void networkStateChange(Context context) {
+ NetworkInfo networkInfo = getCurrentNetworkInfo(context);
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ boolean sendusr1 = prefs.getBoolean("netchangereconnect", true);
+
+
+ String netstatestring;
+ if(networkInfo==null)
+ netstatestring = "not connected";
+ else {
+ String subtype = networkInfo.getSubtypeName();
+ if(subtype==null)
+ subtype = "";
+ String extrainfo = networkInfo.getExtraInfo();
+ if(extrainfo==null)
+ extrainfo="";
+
+ /*
+ if(networkInfo.getType()==android.net.ConnectivityManager.TYPE_WIFI) {
+ WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ WifiInfo wifiinfo = wifiMgr.getConnectionInfo();
+ extrainfo+=wifiinfo.getBSSID();
+
+ subtype += wifiinfo.getNetworkId();
+ }*/
+
+
+
+ netstatestring = String.format("%2$s %4$s to %1$s %3$s",networkInfo.getTypeName(),
+ networkInfo.getDetailedState(),extrainfo,subtype );
+ }
+
+ if(networkInfo!=null && networkInfo.getState() == State.CONNECTED) {
+ int newnet = networkInfo.getType();
+ network = connectState.SHOULDBECONNECTED;
+
+ if(sendusr1 && lastNetwork!=newnet) {
+ if (screen == connectState.PENDINGDISCONNECT)
+ screen = connectState.DISCONNECTED;
+
+ if (lastNetwork==-1){
+ if (screen == connectState.SHOULDBECONNECTED)
+ mManangement.resume();
+ }else{
+ if (screen == connectState.SHOULDBECONNECTED)
+ mManangement.reconnect();
+ }
+
+
+ lastNetwork = newnet;
+ }
+ } else if (networkInfo==null) {
+ // Not connected, stop openvpn, set last connected network to no network
+ lastNetwork=-1;
+ if(sendusr1) {
+ mManangement.pause();
+ network = connectState.DISCONNECTED;
+
+ // Set screen state to be disconnected if it want to disconnect
+ if (screen == connectState.PENDINGDISCONNECT)
+ screen = connectState.DISCONNECTED;
+ }
+ }
+
+
+ if(!netstatestring.equals(lastStateMsg))
+ OpenVPN.logInfo(R.string.netstatus, netstatestring);
+ lastStateMsg=netstatestring;
+
+ }
+
+ private NetworkInfo getCurrentNetworkInfo(Context context) {
+ ConnectivityManager conn = (ConnectivityManager)
+ context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ NetworkInfo networkInfo = conn.getActiveNetworkInfo();
+ return networkInfo;
+ }
+}
diff --git a/src/de/blinkt/openvpn/core/NetworkStateReceiver.java b/src/de/blinkt/openvpn/core/NetworkStateReceiver.java
deleted file mode 100644
index 092de92d..00000000
--- a/src/de/blinkt/openvpn/core/NetworkStateReceiver.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package de.blinkt.openvpn.core;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.State;
-import android.preference.PreferenceManager;
-import de.blinkt.openvpn.R;
-
-public class NetworkStateReceiver extends BroadcastReceiver {
- private int lastNetwork=-1;
- private OpenVPNMangement mManangement;
-
- private String lastStateMsg=null;
-
- public NetworkStateReceiver(OpenVPNMangement magnagement) {
- super();
- mManangement = magnagement;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- NetworkInfo networkInfo = getCurrentNetworkInfo(context);
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- boolean sendusr1 = prefs.getBoolean("netchangereconnect", true);
-
- String netstatestring;
- if(networkInfo==null)
- netstatestring = "not connected";
- else {
- String subtype = networkInfo.getSubtypeName();
- if(subtype==null)
- subtype = "";
- String extrainfo = networkInfo.getExtraInfo();
- if(extrainfo==null)
- extrainfo="";
-
- /*
- if(networkInfo.getType()==android.net.ConnectivityManager.TYPE_WIFI) {
- WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- WifiInfo wifiinfo = wifiMgr.getConnectionInfo();
- extrainfo+=wifiinfo.getBSSID();
-
- subtype += wifiinfo.getNetworkId();
- }*/
-
-
-
- netstatestring = String.format("%2$s %4$s to %1$s %3$s",networkInfo.getTypeName(),
- networkInfo.getDetailedState(),extrainfo,subtype );
- }
-
-
-
- if(networkInfo!=null && networkInfo.getState() == State.CONNECTED) {
- int newnet = networkInfo.getType();
-
- if(sendusr1 && lastNetwork!=newnet) {
- if (lastNetwork==-1)
- mManangement.resume();
- else
- mManangement.reconnect();
- }
-
- lastNetwork = newnet;
- } else if (networkInfo==null) {
- // Not connected, stop openvpn, set last connected network to no network
- lastNetwork=-1;
- if(sendusr1)
- mManangement.pause();
- }
-
- if(!netstatestring.equals(lastStateMsg))
- OpenVPN.logInfo(R.string.netstatus, netstatestring);
- lastStateMsg=netstatestring;
-
- }
-
- private NetworkInfo getCurrentNetworkInfo(Context context) {
- ConnectivityManager conn = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
-
- NetworkInfo networkInfo = conn.getActiveNetworkInfo();
- return networkInfo;
- }
-
-}
diff --git a/src/de/blinkt/openvpn/core/OpenVpnService.java b/src/de/blinkt/openvpn/core/OpenVpnService.java
index dcf53d16..c3ac0629 100644
--- a/src/de/blinkt/openvpn/core/OpenVpnService.java
+++ b/src/de/blinkt/openvpn/core/OpenVpnService.java
@@ -59,7 +59,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
private int mMtu;
private String mLocalIPv6=null;
- private NetworkStateReceiver mNetworkStateReceiver;
+ private DeviceStateReceiver mDeviceStateReceiver;
private boolean mDisplayBytecount=false;
@@ -109,7 +109,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
private void endVpnService() {
mProcessThread=null;
OpenVPN.removeByteCountListener(this);
- unregisterNetworkStateReceiver();
+ unregisterDeviceStateReceiver();
ProfileManager.setConntectedVpnProfileDisconnected(this);
if(!mStarting) {
stopForeground(!mNotificationalwaysVisible);
@@ -226,24 +226,29 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
}
- synchronized void registerNetworkStateReceiver(OpenVPNMangement magnagement) {
+ synchronized void registerDeviceStateReceiver(OpenVPNMangement magnagement) {
// Registers BroadcastReceiver to track network connection changes.
- IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
- mNetworkStateReceiver = new NetworkStateReceiver(magnagement);
- registerReceiver(mNetworkStateReceiver, filter);
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(Intent.ACTION_SCREEN_ON);
+ mDeviceStateReceiver = new DeviceStateReceiver(magnagement);
+ registerReceiver(mDeviceStateReceiver, filter);
+ OpenVPN.addByteCountListener(mDeviceStateReceiver);
}
- synchronized void unregisterNetworkStateReceiver() {
- if(mNetworkStateReceiver!=null)
+ synchronized void unregisterDeviceStateReceiver() {
+ if(mDeviceStateReceiver!=null)
try {
- this.unregisterReceiver(mNetworkStateReceiver);
+ OpenVPN.removeByteCountListener(mDeviceStateReceiver);
+ this.unregisterReceiver(mDeviceStateReceiver);
} catch (IllegalArgumentException iae) {
// I don't know why this happens:
// java.lang.IllegalArgumentException: Receiver not registered: de.blinkt.openvpn.NetworkSateReceiver@41a61a10
// Ignore for now ...
iae.printStackTrace();
}
- mNetworkStateReceiver=null;
+ mDeviceStateReceiver=null;
}
@@ -342,7 +347,10 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
mProcessThread = new Thread(processThread, "OpenVPNProcessThread");
mProcessThread.start();
- registerNetworkStateReceiver(mManagement);
+ if(mDeviceStateReceiver!=null)
+ unregisterDeviceStateReceiver();
+
+ registerDeviceStateReceiver(mManagement);
ProfileManager.setConnectedVpnProfile(this, mProfile);
@@ -361,8 +369,8 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
mProcessThread.interrupt();
}
- if (mNetworkStateReceiver!= null) {
- this.unregisterReceiver(mNetworkStateReceiver);
+ if (mDeviceStateReceiver!= null) {
+ this.unregisterReceiver(mDeviceStateReceiver);
}
// Just in case unregister for state
OpenVPN.removeStateListener(this);