summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--res/drawable/notification_icon.xml20
-rwxr-xr-xres/values/strings.xml3
-rw-r--r--src/de/blinkt/openvpn/OpenVPN.java53
-rw-r--r--src/de/blinkt/openvpn/OpenVpnManagementThread.java16
-rw-r--r--src/de/blinkt/openvpn/OpenVpnService.java104
5 files changed, 139 insertions, 57 deletions
diff --git a/res/drawable/notification_icon.xml b/res/drawable/notification_icon.xml
new file mode 100644
index 00000000..6968e806
--- /dev/null
+++ b/res/drawable/notification_icon.xml
@@ -0,0 +1,20 @@
+<!--
+ <string name="state_auth">Authenticating</string>
+ <string name="state_get_config">Getting client configuration</string>
+ <string name="state_assign_ip">Assigning IP addresses</string>
+ <string name="state_add_routes">Adding routes</string>
+ <string name="state_connected">Connected</string>
+ <string name="state_reconnecting">Reconnecting</string>
+ <string name="state_exiting">Exiting</string>
+ <string name="state_noprocess">Not running</string>
+ <string name="state_resolve">Resolving host names</string>
+ <string name="state_tcp_connect">Connecting (TCP)</string>
+ <string name="state_auth_failed">Authentication failed</string>
+ <string name="state_nonetwork">Waiting for usable network</string>
+ -->
+
+ <level-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:maxLevel="0" android:drawable="@drawable/ic_stat_vpn" />
+ <item android:maxLevel="1" android:drawable="@drawable/ic_stat_vpn" />
+ <item android:maxLevel="2" android:drawable="@drawable/ic_stat_vpn" />
+ </level-list> \ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a101d024..1d1a15e5 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -253,5 +253,6 @@
<string name="state_tcp_connect">Connecting (TCP)</string>
<string name="state_auth_failed">Authentication failed</string>
<string name="state_nonetwork">Waiting for usable network</string>
-
+ <string name="statusline_bytecount">In: %8$1s %8$2s/s Out: %8$3s %8$4s/s</string>
+ <string name="notifcation_title_notconnect">Not connected</string>
</resources>
diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java
index 8d6cb4c8..9cfaf1e8 100644
--- a/src/de/blinkt/openvpn/OpenVPN.java
+++ b/src/de/blinkt/openvpn/OpenVPN.java
@@ -15,18 +15,23 @@ public class OpenVPN {
private static Vector<LogListener> logListener;
private static Vector<StateListener> stateListener;
+ private static Vector<ByteCountListener> byteCountListener;
+
private static String[] mBconfig;
- private static String mLaststatemsg;
+ private static String mLaststatemsg="";
- private static String mLaststate;
+ private static String mLaststate = "NOPROCESS";
private static int mLastStateresid=R.string.state_noprocess;
+
+ private static long mlastByteCount[]={0,0,0,0};
static {
logbuffer = new LinkedList<LogItem>();
logListener = new Vector<OpenVPN.LogListener>();
stateListener = new Vector<OpenVPN.StateListener>();
+ byteCountListener = new Vector<OpenVPN.ByteCountListener>();
logInformation();
}
@@ -83,7 +88,7 @@ public class OpenVPN {
String str = String.format(Locale.ENGLISH,"Log (no context) resid %d", mRessourceId);
if(mArgs !=null)
for(Object o:mArgs)
- str += "|" + o.toString();
+ str += "|" + o.toString();
return str;
}
}
@@ -107,6 +112,10 @@ public class OpenVPN {
public interface StateListener {
void updateState(String state, String logmessage, int localizedResId);
}
+
+ public interface ByteCountListener {
+ void updateByteCount(long in, long out, long diffin, long diffout);
+ }
synchronized static void logMessage(int level,String prefix, String message)
{
@@ -131,14 +140,25 @@ public class OpenVPN {
public synchronized static void removeLogListener(LogListener ll) {
logListener.remove(ll);
}
+
+ public static void addByteCountListener(ByteCountListener bcl) {
+ bcl.updateByteCount(mlastByteCount[0], mlastByteCount[1], mlastByteCount[2], mlastByteCount[3]);
+ byteCountListener.add(bcl);
+ }
+
+ public static void removeByteCountListener(ByteCountListener bcl) {
+ byteCountListener.remove(bcl);
+ }
public synchronized static void addStateListener(StateListener sl){
- stateListener.add(sl);
- if(mLaststate!=null)
- sl.updateState(mLaststate, mLaststatemsg, mLastStateresid);
+ if(!stateListener.contains(sl)){
+ stateListener.add(sl);
+ if(mLaststate!=null)
+ sl.updateState(mLaststate, mLaststatemsg, mLastStateresid);
+ }
}
-
+
private static int getLocalizedState(String state){
if (state.equals("CONNECTING"))
return R.string.state_connecting;
@@ -199,12 +219,10 @@ public class OpenVPN {
}
public synchronized static void updateStateString(String state, String msg, int resid) {
- if (! "BYTECOUNT".equals(state)) {
- mLaststate= state;
- mLaststatemsg = msg;
- mLastStateresid = resid;
- }
-
+ mLaststate= state;
+ mLaststatemsg = msg;
+ mLastStateresid = resid;
+
for (StateListener sl : stateListener) {
sl.updateState(state,msg,resid);
}
@@ -240,4 +258,13 @@ public class OpenVPN {
newlogItem(new LogItem(LogItem.ERROR, ressourceId,args));
}
+ public static void updateByteCount(long in, long out, long diffin, long diffout) {
+ mlastByteCount = new long[] {in,out,diffin,diffout};
+ for(ByteCountListener bcl:byteCountListener){
+ bcl.updateByteCount(in, out, diffin,diffout);
+ }
+ }
+
+
+
}
diff --git a/src/de/blinkt/openvpn/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/OpenVpnManagementThread.java
index 3d68d943..dd3708cf 100644
--- a/src/de/blinkt/openvpn/OpenVpnManagementThread.java
+++ b/src/de/blinkt/openvpn/OpenVpnManagementThread.java
@@ -290,24 +290,12 @@ public class OpenVpnManagementThread implements Runnable {
mLastIn=in;
mLastOut=out;
- 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("BYTECOUNT",netstat);
+ OpenVPN.updateByteCount(in,out,diffin, diffout);
}
- // 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);
- }
+
private void processNeedCommand(String argument) {
int p1 =argument.indexOf('\'');
diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java
index 53ae80b1..0ac57406 100644
--- a/src/de/blinkt/openvpn/OpenVpnService.java
+++ b/src/de/blinkt/openvpn/OpenVpnService.java
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-package de.blinkt.openvpn;
-
-import java.io.IOException;
+package de.blinkt.openvpn;import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Vector;
@@ -34,16 +32,19 @@ import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.net.VpnService;
import android.os.Binder;
-import android.os.Handler;
-import android.os.Handler.Callback;
import android.os.Build;
+import android.os.Handler.Callback;
import android.os.IBinder;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+
import de.blinkt.openvpn.OpenVPN.StateListener;
public class OpenVpnService extends VpnService implements StateListener, Callback {
public static final String START_SERVICE = "de.blinkt.openvpn.START_SERVICE";
+ public static final String START_SERVICE_STICKY = "de.blinkt.openvpn.START_SERVICE_STICKY";
+ public static final String ALWAYS_SHOW_NOTIFICATION = "de.blinkt.openvpn.NOTIFICATION_ALWAYS_VISIBLE";
+
private Thread mProcessThread=null;
@@ -76,15 +77,22 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
public static final int PROTECT_FD = 0;
+
+ private static final int LEVEL_OFFLINE = 0;
+ private static final int LEVEL_NOTCONNECTED = 1;
+ private static final int LEVEL_CONNECTED = 2;
+
+ private static boolean mNotificationalwaysVisible=false;
+
private final IBinder mBinder = new LocalBinder();
-
+
public class LocalBinder extends Binder {
public OpenVpnService getService() {
- // Return this instance of LocalService so clients can call public methods
- return OpenVpnService.this;
- }
- }
-
+ // Return this instance of LocalService so clients can call public methods
+ return OpenVpnService.this;
+ }
+ }
+
@Override
public IBinder onBind(Intent intent) {
String action = intent.getAction();
@@ -93,7 +101,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
else
return super.onBind(intent);
}
-
+
@Override
public void onRevoke() {
OpenVpnManagementThread.stopOpenVPN();
@@ -115,27 +123,31 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
}
}
- private void showNotification(String msg, String tickerText, boolean lowpriority, long when) {
+ private void showNotification(String msg, String tickerText, boolean lowpriority, long when, int level) {
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
- int icon = R.drawable.ic_stat_vpn;
+ int icon = R.drawable.notification_icon;
android.app.Notification.Builder nbuilder = new Notification.Builder(this);
- nbuilder.setContentTitle(getString(R.string.notifcation_title,mProfile.mName));
+ if(mProfile!=null)
+ nbuilder.setContentTitle(getString(R.string.notifcation_title,mProfile.mName));
+ else
+ nbuilder.setContentTitle(getString(R.string.notifcation_title_notconnect));
+
nbuilder.setContentText(msg);
nbuilder.setOnlyAlertOnce(true);
nbuilder.setOngoing(true);
nbuilder.setContentIntent(getLogPendingIntent());
- nbuilder.setSmallIcon(icon);
+ nbuilder.setSmallIcon(icon,level);
if(when !=0)
nbuilder.setWhen(when);
// Try to set the priority available since API 16 (Jellybean)
jbNotificationExtras(lowpriority, nbuilder);
- if(tickerText!=null)
+ if(tickerText!=null && !tickerText.equals(""))
nbuilder.setTicker(tickerText);
@SuppressWarnings("deprecation")
@@ -220,11 +232,19 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
@Override
- public int onStartCommand(Intent intent, int flags, int startId) {
-
+ public int onStartCommand(Intent intent, int flags, int startId) {
+
+ if(intent != null && intent.getBooleanExtra(ALWAYS_SHOW_NOTIFICATION, false))
+ mNotificationalwaysVisible=true;
+
+ OpenVPN.addStateListener(this);
+
if(intent != null && intent.getAction() !=null &&intent.getAction().equals(START_SERVICE))
return START_NOT_STICKY;
-
+ if(intent != null && intent.getAction() !=null &&intent.getAction().equals(START_SERVICE_STICKY)) {
+ return START_REDELIVER_INTENT;
+ }
+
// Extract information from the intent.
String prefix = getPackageName();
@@ -234,10 +254,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
mProfile = ProfileManager.get(profileUUID);
- showNotification("Starting VPN " + mProfile.mName,"Starting VPN " + mProfile.mName, false,0);
+ showNotification("Starting VPN " + mProfile.mName,"Starting VPN " + mProfile.mName, false,0,LEVEL_NOTCONNECTED);
- OpenVPN.addStateListener(this);
// Set a flag that we are starting a new VPN
mStarting=true;
@@ -469,20 +488,23 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
public void updateState(String state,String logmessage, int resid) {
// If the process is not running, ignore any state,
// Notification should be invisible in this state
- if(mProcessThread==null)
+ if(mProcessThread==null && !mNotificationalwaysVisible)
return;
// Display byte count only after being connected
- if("BYTECOUNT".equals(state)) {
- if(mDisplayBytecount) {
- showNotification(logmessage,null,true,mConnecttime);
- }
- } else {
+ {
+ int level;
if("CONNECTED".equals(state)) {
mDisplayBytecount = true;
mConnecttime = System.currentTimeMillis();
+ level = LEVEL_CONNECTED;
} else {
+ if ("NONETWORK".equals(state)) {
+ level = LEVEL_OFFLINE;
+ } else {
+ level = LEVEL_NOTCONNECTED;
+ }
mDisplayBytecount = false;
}
@@ -490,11 +512,35 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
// This also mean we are no longer connected, ignore bytecount messages until next
// CONNECTED
String ticker = getString(resid);
- showNotification(getString(resid) +" " + logmessage,ticker,false,0);
+ showNotification(getString(resid) +" " + logmessage,ticker,false,0, level);
}
}
+
+ public void updateByteCount(long in, long out, long diffin, long diffout) {
+ if(mDisplayBytecount) {
+ String netstat = String.format(getString(R.string.statusline_bytecount),
+ humanReadableByteCount(in, false),
+ humanReadableByteCount(diffin, false),
+ humanReadableByteCount(out, false),
+ humanReadableByteCount(diffout, false));
+
+ boolean lowpriority = !mNotificationalwaysVisible;
+ showNotification(netstat,null,lowpriority,mConnecttime, LEVEL_CONNECTED);
+ }
+
+ }
+
+ // 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);
+ }
+
@Override
public boolean handleMessage(Message msg) {
Runnable r = msg.getCallback();