From 06917978c727df00627a5b831526def8d613a280 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Mon, 18 Jun 2012 00:27:03 +0200 Subject: Add a status message which shows the status of the connecting/connected VPN --- proguard.cfg | 40 ------------- res/values/strings.xml | 13 +++-- res/xml/general_settings.xml | 10 ++++ src/de/blinkt/openvpn/LaunchVPN.java | 60 ++++++++++--------- src/de/blinkt/openvpn/LogWindow.java | 4 +- src/de/blinkt/openvpn/NetworkSateReceiver.java | 1 - src/de/blinkt/openvpn/OpenVPN.java | 16 ++++- src/de/blinkt/openvpn/OpenVPNThread.java | 2 +- src/de/blinkt/openvpn/OpenVpnManagementThread.java | 40 +++++++------ src/de/blinkt/openvpn/OpenVpnService.java | 68 ++++++++++++++++++---- todo.txt | 10 ---- 11 files changed, 147 insertions(+), 117 deletions(-) delete mode 100644 proguard.cfg 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 ; -} - --keepclasseswithmembers class * { - public (android.content.Context, android.util.AttributeSet); -} - --keepclasseswithmembers class * { - public (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 @@ 1194 Location folder can\'t be read! + Select Cancel No Data LZO Compression @@ -32,6 +33,7 @@ Client Certificate Key PKCS12 File CA Certificate + Select Nothing selected Copyright © 2002–2010 OpenVPN Technologies, Inc. <sales@openvpn.net>\n @@ -55,7 +57,6 @@ All your precious VPNs Type PKCS12 Password - Select… Select… Nothing Selected Use TLS Authentication @@ -212,6 +213,10 @@ Network Status: %s The CA cert is usually returned from the Android Keystore. Specify a seperate certificate if you get certificate verification errors. Select - No CA Certificate returned while reading from Android keystore. Auhtentication will probably fail. - - + No CA Certificate returned while reading from Android keystore. Auhtentication will probably fail. + Shows the log window on connect. The log window can always be accessed from the notification status. + Show log window + Keep the notification displayed after the connection is established to show traffic statistics. + Show Traffic Statistics + + \ 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" /> + + \ 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 mFDList=new LinkedList(); private int mBytecountinterval=2; private long mLastIn=0; - private long mLastOut=0; + private long mLastOut=0; + private String mCurrentstate; private static Vector active=new Vector(); @@ -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 mDnslist=new Vector(); @@ -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); + } + } + } diff --git a/todo.txt b/todo.txt index bb5135f8..06948a72 100644 --- a/todo.txt +++ b/todo.txt @@ -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 - -- cgit v1.2.3