From fa4b5e8c373ff19d8cc96f5bb7f636598ff279cd Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 25 May 2013 11:49:49 +0200 Subject: 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 --- .../blinkt/openvpn/core/DeviceStateReceiver.java | 202 +++++++++++++++++++++ .../blinkt/openvpn/core/NetworkStateReceiver.java | 90 --------- src/de/blinkt/openvpn/core/OpenVpnService.java | 34 ++-- 3 files changed, 223 insertions(+), 103 deletions(-) create mode 100644 src/de/blinkt/openvpn/core/DeviceStateReceiver.java delete mode 100644 src/de/blinkt/openvpn/core/NetworkStateReceiver.java (limited to 'src/de/blinkt') 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 trafficdata = new LinkedList(); + + @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); -- cgit v1.2.3