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 --- res/values/strings.xml | 4 + res/xml/general_settings.xml | 17 +- .../blinkt/openvpn/core/DeviceStateReceiver.java | 202 +++++++++++++++++++++ .../blinkt/openvpn/core/NetworkStateReceiver.java | 90 --------- src/de/blinkt/openvpn/core/OpenVpnService.java | 34 ++-- 5 files changed, 235 insertions(+), 112 deletions(-) create mode 100644 src/de/blinkt/openvpn/core/DeviceStateReceiver.java delete mode 100644 src/de/blinkt/openvpn/core/NetworkStateReceiver.java 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 @@ No app allowed to use external API Allowed apps: %s Clear list of allowed external apps?\nCurrent list of allowed apps:\n\n%s + "Pause VPN when screen is off and less than 64 kB transferred data in 60s." + Pause VPN connection after screen off + Pausing connection in screen off state: less than %1$s in %2$ss + ERROR: Persistent tun not enabled for this VPN. Ignoring option to pause VPN when screen is off \ 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" /> - + + + android:persistent="false" + android:title="Clear allowed external apps" /> 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