diff options
| -rwxr-xr-x | res/values/strings.xml | 4 | ||||
| -rw-r--r-- | res/xml/general_settings.xml | 17 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/core/DeviceStateReceiver.java | 202 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/core/NetworkStateReceiver.java | 90 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/core/OpenVpnService.java | 34 | 
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); | 
