diff options
| -rw-r--r-- | proguard.cfg | 40 | ||||
| -rw-r--r-- | res/values/strings.xml | 13 | ||||
| -rw-r--r-- | res/xml/general_settings.xml | 10 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/LaunchVPN.java | 60 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/LogWindow.java | 4 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/NetworkSateReceiver.java | 1 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVPN.java | 16 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVPNThread.java | 2 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVpnManagementThread.java | 40 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVpnService.java | 68 | ||||
| -rw-r--r-- | todo.txt | 10 | 
11 files changed, 147 insertions, 117 deletions
| diff --git a/proguard.cfg b/proguard.cfg deleted file mode 100644 index b1cdf17b..00000000 --- a/proguard.cfg +++ /dev/null @@ -1,40 +0,0 @@ --optimizationpasses 5 --dontusemixedcaseclassnames --dontskipnonpubliclibraryclasses --dontpreverify --verbose --optimizations !code/simplification/arithmetic,!field/*,!class/merging/* - --keep public class * extends android.app.Activity --keep public class * extends android.app.Application --keep public class * extends android.app.Service --keep public class * extends android.content.BroadcastReceiver --keep public class * extends android.content.ContentProvider --keep public class * extends android.app.backup.BackupAgentHelper --keep public class * extends android.preference.Preference --keep public class com.android.vending.licensing.ILicensingService - --keepclasseswithmembernames class * { -    native <methods>; -} - --keepclasseswithmembers class * { -    public <init>(android.content.Context, android.util.AttributeSet); -} - --keepclasseswithmembers class * { -    public <init>(android.content.Context, android.util.AttributeSet, int); -} - --keepclassmembers class * extends android.app.Activity { -   public void *(android.view.View); -} - --keepclassmembers enum * { -    public static **[] values(); -    public static ** valueOf(java.lang.String); -} - --keep class * implements android.os.Parcelable { -  public static final android.os.Parcelable$Creator *; -} diff --git a/res/values/strings.xml b/res/values/strings.xml index f7c9817f..423ad066 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -24,6 +24,7 @@      <string name="defaultport" translatable="false">1194</string>      <string name="location">Location</string>      <string name="cant_read_folder">folder can\'t be read!</string> +    <string name="select">Select</string>      <string name="cancel">Cancel</string>      <string name="no_data">No Data</string>      <string name="useLZO">LZO Compression</string> @@ -32,6 +33,7 @@      <string name="client_key_title">Client Certificate Key</string>      <string name="client_pkcs12_title">PKCS12 File</string>      <string name="ca_title">CA Certificate</string> +    <string name="select_certificate">Select</string>      <string name="no_certificate">Nothing selected</string>      <string name="opevpn_copyright" translatable="false">Copyright © 2002–2010 OpenVPN Technologies, Inc. <sales@openvpn.net>\n @@ -55,7 +57,6 @@      <string name="vpn_list_title">All your precious VPNs</string>      <string name="vpn_type">Type</string>      <string name="pkcs12pwquery">PKCS12 Password</string> -    <string name="select">Select…</string>      <string name="file_select">Select…</string>      <string name="file_nothing_selected">Nothing Selected</string>      <string name="useTLSAuth">Use TLS Authentication</string> @@ -212,6 +213,10 @@      <string name="netstatus">Network Status: %s</string>      <string name="extracahint">The CA cert is usually returned from the Android Keystore. Specify a seperate certificate if you get certificate verification errors.</string>      <string name="select_file">Select</string> -        <string name="keychain_nocacert">No CA Certificate returned while reading from Android keystore. Auhtentication will probably fail.</string> -     -</resources> +    <string name="keychain_nocacert">No CA Certificate returned while reading from Android keystore. Auhtentication will probably fail.</string> +    <string name="show_log_summary">Shows the log window on connect. The log window can always be accessed from the notification status.</string> +    <string name="show_log_window">Show log window</string> +    <string name="keppstatus_summary">Keep the notification displayed after the connection is established to show traffic statistics.</string> +    <string name="keepstatus">Show Traffic Statistics</string> + +</resources>
\ No newline at end of file diff --git a/res/xml/general_settings.xml b/res/xml/general_settings.xml index 74c8965f..2da80cc6 100644 --- a/res/xml/general_settings.xml +++ b/res/xml/general_settings.xml @@ -11,5 +11,15 @@          android:key="useCM9Fix"          android:summary="@string/owner_fix_summary"          android:title="@string/owner_fix" /> +    <CheckBoxPreference +        android:defaultValue="false" +        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" />  </PreferenceScreen>
\ No newline at end of file diff --git a/src/de/blinkt/openvpn/LaunchVPN.java b/src/de/blinkt/openvpn/LaunchVPN.java index e76057d7..1c873f22 100644 --- a/src/de/blinkt/openvpn/LaunchVPN.java +++ b/src/de/blinkt/openvpn/LaunchVPN.java @@ -44,7 +44,6 @@ import android.widget.ArrayAdapter;  import android.widget.EditText;  import android.widget.ListView;  import android.widget.TextView; -import android.widget.Toast;  /**   * This Activity actually handles two stages of a launcher shortcut's life cycle. @@ -80,11 +79,11 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener {  	private ProfileManager mPM;  	private VpnProfile mSelectedProfile; -	 -	 + +  	private boolean mCmfixed=false;  	static boolean minivpnwritten=false; -	 +  	@Override  	public void onCreate(Bundle icicle) {  		super.onCreate(icicle); @@ -92,7 +91,7 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener {  		mPM =ProfileManager.getInstance(this);  	} -	 +  	@Override  	protected void onStart() {  		super.onStart(); @@ -100,6 +99,7 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener {  		final Intent intent = getIntent();  		final String action = intent.getAction(); +		  		// If the intent is a request to create a shortcut, we'll do that and exit  		if(Intent.ACTION_MAIN.equals(action)) { @@ -110,10 +110,11 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener {  			VpnProfile profileToConnect = ProfileManager.get(shortcutUUID);  			if(shortcutName != null && profileToConnect ==null)  				profileToConnect = ProfileManager.getInstance(this).getProfileByName(shortcutName); -			 +  			if(profileToConnect ==null) { -				Toast notfound = Toast.makeText(this, R.string.shortcut_profile_notfound, Toast.LENGTH_SHORT); -				notfound.show(); +				OpenVPN.logError(R.string.shortcut_profile_notfound); +				// show Log window to display error +				showLogWindow();  				finish();  				return;  			} @@ -221,31 +222,31 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener {  		//    }  	} -	 +  	private boolean writeMiniVPN() {  		File mvpnout = new File(getCacheDir(),"minivpn");  		if (mvpnout.exists() && mvpnout.canExecute())  			return true; -			 +  		if(minivpnwritten)  			return true;  		try {  			InputStream mvpn = getAssets().open("minivpn"); -			 +  			FileOutputStream fout = new FileOutputStream(mvpnout); -			 +  			byte buf[]= new byte[4096]; -			 +  			int lenread = mvpn.read(buf);  			while(lenread> 0) {  				fout.write(buf, 0, lenread);  				lenread = mvpn.read(buf);  			}  			fout.close(); -			 +  			if(!mvpnout.setExecutable(true))  				return false; -			 +  			minivpnwritten=true;  			return true;  		} catch (IOException e) { @@ -303,26 +304,36 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener {  				if(needpw !=0) {  					askForPW(needpw);  				} else { +					SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);         +					boolean showlogwindow = prefs.getBoolean("showlogwindow", false); +					if(showlogwindow) +						showLogWindow();  					new startOpenVpnThread().start();  				} -  			} else if (resultCode == Activity.RESULT_CANCELED) {  				// User does not want us to start, so we just vanish  				finish();  			}  		}  	} +	void showLogWindow() { + +		Intent startLW = new Intent(getBaseContext(),LogWindow.class); +		startLW.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); +		startActivity(startLW); + +	}  	void showConfigErrorDialog(int vpnok) {  		AlertDialog.Builder d = new AlertDialog.Builder(this);  		d.setTitle(R.string.config_error_found);  		d.setMessage(vpnok);  		d.setPositiveButton(android.R.string.ok, new OnClickListener() { -			 +  			@Override  			public void onClick(DialogInterface dialog, int which) {  				finish(); -				 +  			}  		});  		d.show(); @@ -339,7 +350,7 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener {  		// Check if we want to fix /dev/tun  		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);          		boolean usecm9fix = prefs.getBoolean("useCM9Fix", false); -		 +  		if(usecm9fix && !mCmfixed ) {  			ProcessBuilder pb = new ProcessBuilder(new String[] {"su","-c","chown system /dev/tun"});  			try { @@ -353,8 +364,8 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener {  				e.printStackTrace();  			}  		} -			 -		 + +  		if (intent != null) {  			// Start the query @@ -363,7 +374,8 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener {  			} catch (ActivityNotFoundException ane) {  				// Shame on you Sony! At least one user reported that   				// an official Sony Xperia Arc S image triggers this exception -				Toast.makeText(this, R.string.no_vpn_support_image, Toast.LENGTH_LONG).show(); +				OpenVPN.logError(R.string.no_vpn_support_image); +				showLogWindow();  			}  		} else {  			onActivityResult(START_VPN_PROFILE, Activity.RESULT_OK, null); @@ -379,10 +391,6 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener {  		}  		void startOpenVpn() { -			Intent startLW = new Intent(getBaseContext(),LogWindow.class); -			startLW.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); -			startActivity(startLW); -			  			if(!writeMiniVPN()) {  				OpenVPN.logMessage(0, "", "Error writing minivpn binary");  				return; diff --git a/src/de/blinkt/openvpn/LogWindow.java b/src/de/blinkt/openvpn/LogWindow.java index 6060e7ad..8fadf3ad 100644 --- a/src/de/blinkt/openvpn/LogWindow.java +++ b/src/de/blinkt/openvpn/LogWindow.java @@ -271,12 +271,12 @@ public class LogWindow extends ListActivity implements StateListener  {  	}  	@Override -	public void updateState(final String logmessage) { +	public void updateState(final String status,final String logmessage) {  		runOnUiThread(new Runnable() {  			@Override  			public void run() { -				mSpeedView.setText(logmessage); +				mSpeedView.setText(status + " " + logmessage);  			}  		}); diff --git a/src/de/blinkt/openvpn/NetworkSateReceiver.java b/src/de/blinkt/openvpn/NetworkSateReceiver.java index a8d69896..0758cf3a 100644 --- a/src/de/blinkt/openvpn/NetworkSateReceiver.java +++ b/src/de/blinkt/openvpn/NetworkSateReceiver.java @@ -26,7 +26,6 @@ public class NetworkSateReceiver extends BroadcastReceiver {  		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);        
  		boolean sendusr1 = prefs.getBoolean("netchangereconnect", true);
 -
  		String netstatestring;
  		if(networkInfo==null)
  			netstatestring = "not connected";
 diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java index b09eb60e..c23ee56d 100644 --- a/src/de/blinkt/openvpn/OpenVPN.java +++ b/src/de/blinkt/openvpn/OpenVPN.java @@ -41,6 +41,12 @@ public class OpenVPN {  		} +		public LogItem(int loglevel, int ressourceId) { +			mRessourceId =ressourceId; +			mLevel = loglevel; +		} + +  		String getString(Context c) {  			if(mMessage !=null) {  				return mMessage; @@ -73,7 +79,7 @@ public class OpenVPN {  	}  	public interface StateListener { -		void updateState(String logmessage); +		void updateState(String state, String logmessage);  	}  	synchronized static void logMessage(int level,String prefix, String message) @@ -126,9 +132,9 @@ public class OpenVPN {  	} -	public static void updateStateString(String msg) { +	public static void updateStateString(String state, String msg) {  		for (StateListener sl : stateListener) { -			sl.updateState(msg); +			sl.updateState(state,msg);  		}  	} @@ -155,6 +161,10 @@ public class OpenVPN {  	} +	public static void logError(int ressourceId) { +		newlogItem(new LogItem(LogItem.ERROR, ressourceId)); +	} +  } diff --git a/src/de/blinkt/openvpn/OpenVPNThread.java b/src/de/blinkt/openvpn/OpenVPNThread.java index fdb0ac02..22a08763 100644 --- a/src/de/blinkt/openvpn/OpenVPNThread.java +++ b/src/de/blinkt/openvpn/OpenVPNThread.java @@ -41,7 +41,7 @@ public class OpenVPNThread implements Runnable {  			//mInterface = null;
 -			OpenVPN.updateStateString("No process running");
 +			OpenVPN.updateStateString("NOPROCESS","No process running");
  			// Not a good place to do it, but will do
  			OpenVPN.logBuilderConfig(null);
  			Log.i(TAG, "Exiting");
 diff --git a/src/de/blinkt/openvpn/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/OpenVpnManagementThread.java index 012e0923..f23d9d9b 100644 --- a/src/de/blinkt/openvpn/OpenVpnManagementThread.java +++ b/src/de/blinkt/openvpn/OpenVpnManagementThread.java @@ -21,7 +21,8 @@ public class OpenVpnManagementThread implements Runnable {  	private LinkedList<FileDescriptor> mFDList=new LinkedList<FileDescriptor>();
  	private int mBytecountinterval=2;
  	private long mLastIn=0; 
 -	private long mLastOut=0; 
 +	private long mLastOut=0;
 +	private String mCurrentstate; 
  	private static Vector<OpenVpnManagementThread> active=new Vector<OpenVpnManagementThread>();
 @@ -185,8 +186,9 @@ public class OpenVpnManagementThread implements Runnable {  	}
  	private void processState(String argument) {
 -		String[] args = argument.split(",",2);
 -		OpenVPN.updateStateString(args[1]);
 +		String[] args = argument.split(",",3);
 +		mCurrentstate = args[1];
 +		OpenVPN.updateStateString(mCurrentstate,args[2]);
  	}
 @@ -195,32 +197,32 @@ public class OpenVpnManagementThread implements Runnable {  		int comma = argument.indexOf(',');
  		long in = Long.parseLong(argument.substring(0, comma));
  		long out = Long.parseLong(argument.substring(comma+1));
 -		
 +
  		long diffin = in - mLastIn; 
  		long diffout = out - mLastOut;
 -		
 +
  		mLastIn=in;
  		mLastOut=out;
 -		
 -		String netstat = String.format("In: %8s, %8s/s     Out %8s, %8s/s  ",
 +
 +		String netstat = String.format("In: %8s, %8s/s  Out %8s, %8s/s",
  				humanReadableByteCount(in, false),
  				humanReadableByteCount(diffin, false),
  				humanReadableByteCount(out, false),
  				humanReadableByteCount(diffout, false));
 -		OpenVPN.updateStateString(netstat);
 -				
 -		
 +		OpenVPN.updateStateString("BYTECOUNT",netstat);
 +
 +
  	}
  	// From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java
  	public static String humanReadableByteCount(long bytes, boolean si) {
 -	    int unit = si ? 1000 : 1024;
 -	    if (bytes < unit) return bytes + " B";
 -	    int exp = (int) (Math.log(bytes) / Math.log(unit));
 -	    String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");
 -	    return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
 +		int unit = si ? 1000 : 1024;
 +		if (bytes < unit) return bytes + " B";
 +		int exp = (int) (Math.log(bytes) / Math.log(unit));
 +		String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");
 +		return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
  	}
 -	
 +
  	private void processNeedCommand(String argument) {
  		int p1 =argument.indexOf('\'');
  		int p2 = argument.indexOf('\'',p1+1);
 @@ -328,10 +330,10 @@ public class OpenVpnManagementThread implements Runnable {  	private void processPWCommand(String argument) {
  		//argument has the form 	Need 'Private Key' password
 -		
 +
  		String needed;
  		try{
 -			
 +
  			int p1 = argument.indexOf('\'');
  			int p2 = argument.indexOf('\'',p1+1);
  			needed = argument.substring(p1+1, p2);
 @@ -384,7 +386,7 @@ public class OpenVpnManagementThread implements Runnable {  	public void reconnect() {
  		managmentCommand("signal SIGUSR1\n");
 -		
 +
  	}
  }
 diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index 8c172115..a0d7503d 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -19,19 +19,24 @@ package de.blinkt.openvpn;  import java.io.IOException;  import java.util.Vector; +import de.blinkt.openvpn.OpenVPN.StateListener; +  import android.app.Notification; +import android.app.Notification.Builder;  import android.app.NotificationManager;  import android.app.PendingIntent;  import android.content.Context;  import android.content.Intent;  import android.content.IntentFilter; +import android.content.SharedPreferences;  import android.net.ConnectivityManager;  import android.net.LocalSocket;  import android.net.LocalSocketAddress;  import android.net.VpnService;  import android.os.ParcelFileDescriptor; +import android.preference.PreferenceManager; -public class OpenVpnService extends VpnService { +public class OpenVpnService extends VpnService implements StateListener {  	private Thread mServiceThread;  	private Vector<String> mDnslist=new Vector<String>(); @@ -54,7 +59,9 @@ public class OpenVpnService extends VpnService {  	private NetworkSateReceiver mNetworkStateReceiver; -	private static final int HELLO_ID = 1; +	private boolean mDisplayBytecount=false; + +	private static final int OPENVPN_STATUS = 1;  	@Override  	public void onRevoke() { @@ -63,24 +70,36 @@ public class OpenVpnService extends VpnService {  		stopSelf();  	}; -	private void showNotification() { +	private void hideNotification() { +		String ns = Context.NOTIFICATION_SERVICE; +		NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns); +		mNotificationManager.cancel(OPENVPN_STATUS); +		 +	} +	private void showNotification(String msg) {  		String ns = Context.NOTIFICATION_SERVICE;  		NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);  		int icon = R.drawable.icon; -		CharSequence tickerText = "Hello";  		long when = System.currentTimeMillis(); +		 +		android.app.Notification.Builder nbuilder = new Notification.Builder(this); -		mNotification = new Notification(icon, tickerText, when); +		nbuilder.setContentTitle("OpenVPN - "  + mProfile.mName); +		nbuilder.setContentText(msg); +		nbuilder.setOnlyAlertOnce(true); +		nbuilder.setOngoing(true); +		nbuilder.setContentIntent(getLogPendingIntent()); +		nbuilder.setSmallIcon(icon); +		nbuilder.setWhen(when); -		Context context = getApplicationContext(); -		CharSequence contentTitle = "My notification"; -		CharSequence contentText = "Hello World!"; +		mNotification = nbuilder.getNotification(); -		mNotification.setLatestEventInfo(context, contentTitle, contentText, getLogPendingIntent()); -		mNotificationManager.notify(HELLO_ID, mNotification); +		 + +		mNotificationManager.notify(OPENVPN_STATUS, mNotification);  	} @@ -135,7 +154,7 @@ public class OpenVpnService extends VpnService {  		String profileUUID = intent.getStringExtra(prefix + ".profileUUID");  		mProfile = ProfileManager.get(profileUUID); -		//showNotification(); +		OpenVPN.addSpeedListener(this);  		// Stop the previous session by interrupting the thread.  		if(OpenVpnManagementThread.stopOpenVPN()){ @@ -357,4 +376,31 @@ public class OpenVpnService extends VpnService {  		mLocalIPv6 = ipv6addr;  	} +	@Override +	public void updateState(String state,String logmessage) { +		if("NOPROCESS".equals(state)) { +			hideNotification(); +			mDisplayBytecount=false; +			return; +		} +		 +		if("CONNECTED".equals(state)) { +			SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);         +			mDisplayBytecount = prefs.getBoolean("statusafterconnect", false); +			if(!mDisplayBytecount) { +				hideNotification(); +				return; +			}			 +		} +		 +		if("BYTECOUNT".equals(state)) { +			if(mDisplayBytecount) { +				showNotification(logmessage); +			} +		} else { +			// Other notifications are shown +			showNotification(state +" " + logmessage); +		} +	} +  } @@ -9,16 +9,10 @@ Ideas:  - implement general settings dialog     - encryption of profiles     - Speed/Transfered in notification bar (byte counter of management)  -   - Kick openvpn on network state change (Wifi <-> GPRS/EDGE/UMTS) - - rework logging system (first step: rename OpenVPN class to samething sensible)  -  - map SIGUSR1 to SIGINT  - add a put this certificate into file obscure option -- adding a profile should bring up editing the profile instantly - -  Bugfixes:   - startpath file explorer @@ -38,7 +32,3 @@ Tap support:     - implement arp, possible the most difficult task ...        - need to chose right mac of receiver -Requested by users: -auth -mtu-link - | 
