From 180642560ef5c8a0139dcd50c1a7fa949c0c20f4 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sun, 23 Jun 2013 15:09:09 +0200 Subject: Implement expandable notifications for 4.1 --- src/de/blinkt/openvpn/LogWindow.java | 88 ++++++------- .../blinkt/openvpn/core/DeviceStateReceiver.java | 143 +++++++++++++-------- src/de/blinkt/openvpn/core/OpenVPN.java | 43 ++++--- src/de/blinkt/openvpn/core/OpenVPNManagement.java | 10 +- .../openvpn/core/OpenVpnManagementThread.java | 83 +++++++----- src/de/blinkt/openvpn/core/OpenVpnService.java | 73 ++++++++--- 6 files changed, 278 insertions(+), 162 deletions(-) (limited to 'src') diff --git a/src/de/blinkt/openvpn/LogWindow.java b/src/de/blinkt/openvpn/LogWindow.java index 5c78f2f6..1d75c154 100644 --- a/src/de/blinkt/openvpn/LogWindow.java +++ b/src/de/blinkt/openvpn/LogWindow.java @@ -1,21 +1,8 @@ package de.blinkt.openvpn; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.Vector; - import android.app.AlertDialog; -import android.app.AlertDialog.Builder; import android.app.ListActivity; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.ComponentName; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.ServiceConnection; +import android.content.*; import android.database.DataSetObserver; import android.os.Bundle; import android.os.Handler; @@ -23,17 +10,9 @@ import android.os.Handler.Callback; import android.os.IBinder; import android.os.Message; import android.text.format.DateFormat; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; +import android.view.*; +import android.widget.*; import android.widget.AdapterView.OnItemLongClickListener; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.Toast; import de.blinkt.openvpn.core.OpenVPN; import de.blinkt.openvpn.core.OpenVPN.ConnectionStatus; import de.blinkt.openvpn.core.OpenVPN.LogItem; @@ -43,6 +22,11 @@ import de.blinkt.openvpn.core.OpenVpnService; import de.blinkt.openvpn.core.OpenVpnService.LocalBinder; import de.blinkt.openvpn.core.ProfileManager; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.Vector; + public class LogWindow extends ListActivity implements StateListener { private static final String LOGTIMEFORMAT = "logtimeformat"; private static final int START_VPN_CONFIG = 0; @@ -259,28 +243,32 @@ public class LogWindow extends ListActivity implements StateListener { private LogWindowListAdapter ladapter; private TextView mSpeedView; + private void showDisconnectDialog(final OpenVpnService service) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.title_cancel); + builder.setMessage(R.string.cancel_connection_query); + builder.setNegativeButton(android.R.string.no, null); + builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - @Override + @Override + public void onClick(DialogInterface dialog, int which) { + ProfileManager.setConntectedVpnProfileDisconnected(LogWindow.this); + if(service.getManagement()!=null) + service.getManagement().stopVPN(); + } + }); + + builder.show(); + } + + + @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId()==R.id.clearlog) { ladapter.clearLog(); return true; } else if(item.getItemId()==R.id.cancel){ - Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.title_cancel); - builder.setMessage(R.string.cancel_connection_query); - builder.setNegativeButton(android.R.string.no, null); - builder.setPositiveButton(android.R.string.yes, new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - ProfileManager.setConntectedVpnProfileDisconnected(getApplicationContext()); - if(mService.getManagement()!=null) - mService.getManagement().stopVPN(); - } - }); - - builder.show(); + showDisconnectDialog(mService); return true; } else if(item.getItemId()==R.id.send) { ladapter.shareLog(); @@ -313,7 +301,7 @@ public class LogWindow extends ListActivity implements StateListener { } - @Override + @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.logmenu, menu); @@ -325,9 +313,21 @@ public class LogWindow extends ListActivity implements StateListener { protected void onResume() { super.onResume(); OpenVPN.addStateListener(this); - } - @Override + if (getIntent() !=null && OpenVpnService.DISCONNECT_VPN.equals(getIntent().getAction())) + showDisconnectDialog(mService); + + setIntent(null); + + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + } + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == START_VPN_CONFIG && resultCode==RESULT_OK) { String configuredVPN = data.getStringExtra(VpnProfile.EXTRA_PROFILEUUID); @@ -402,7 +402,7 @@ public class LogWindow extends ListActivity implements StateListener { } - @Override + @Override public void updateState(final String status,final String logmessage, final int resid, final ConnectionStatus level) { runOnUiThread(new Runnable() { diff --git a/src/de/blinkt/openvpn/core/DeviceStateReceiver.java b/src/de/blinkt/openvpn/core/DeviceStateReceiver.java index d5029b07..ecdf5c55 100644 --- a/src/de/blinkt/openvpn/core/DeviceStateReceiver.java +++ b/src/de/blinkt/openvpn/core/DeviceStateReceiver.java @@ -13,9 +13,11 @@ import de.blinkt.openvpn.core.OpenVPN.ByteCountListener; import java.util.LinkedList; +import static de.blinkt.openvpn.core.OpenVPNManagement.pauseReason; + public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountListener { - private int lastNetwork=-1; - private OpenVPNManagement mManangement; + private int lastNetwork = -1; + private OpenVPNManagement mManagement; // Window time in s private final int TRAFFIC_WINDOW = 60; @@ -23,10 +25,11 @@ public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountL private final long TRAFFIC_LIMIT = 64 * 1024; - connectState network= connectState.DISCONNECTED; + connectState network = connectState.DISCONNECTED; connectState screen = connectState.SHOULDBECONNECTED; + connectState userpause = connectState.SHOULDBECONNECTED; - private String lastStateMsg=null; + private String lastStateMsg = null; enum connectState { SHOULDBECONNECTED, @@ -35,8 +38,7 @@ public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountL } static class Datapoint { - private Datapoint(long t, long d) - { + private Datapoint(long t, long d) { timestamp = t; data = d; } @@ -49,34 +51,49 @@ public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountL @Override public void updateByteCount(long in, long out, long diffin, long diffout) { - if (screen!=connectState.PENDINGDISCONNECT) + if (screen != connectState.PENDINGDISCONNECT) return; long total = diffin + diffout; - trafficdata.add(new Datapoint(System.currentTimeMillis(),total)); + trafficdata.add(new Datapoint(System.currentTimeMillis(), total)); - while(trafficdata.getFirst().timestamp <= (System.currentTimeMillis() - TRAFFIC_WINDOW*1000)) { + while (trafficdata.getFirst().timestamp <= (System.currentTimeMillis() - TRAFFIC_WINDOW * 1000)) { trafficdata.removeFirst(); } long windowtraffic = 0; - for (Datapoint dp: trafficdata) + 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); + if (windowtraffic < TRAFFIC_LIMIT) { + screen = connectState.DISCONNECTED; + OpenVPN.logInfo(R.string.screenoff_pause, + OpenVpnService.humanReadableByteCount(TRAFFIC_LIMIT, false), TRAFFIC_WINDOW); - mManangement.pause(); - } + mManagement.pause(getPauseReason()); + } } + public void userPause(boolean pause) { + if (pause) { + userpause = connectState.DISCONNECTED; + // Check if we should disconnect + mManagement.pause(getPauseReason()); + } else { + boolean wereConnected = shouldBeConnected(); + userpause = connectState.SHOULDBECONNECTED; + if (shouldBeConnected() && !wereConnected) + mManagement.resume(); + else + // Update the reason why we currently paused + mManagement.pause(getPauseReason()); + } + } public DeviceStateReceiver(OpenVPNManagement magnagement) { super(); - mManangement = magnagement; + mManagement = magnagement; } @@ -85,31 +102,36 @@ public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountL SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - if(ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) { + if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) { networkStateChange(context); } else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { - boolean screenoff = prefs.getBoolean("screenoff", false); + boolean screenOff = prefs.getBoolean("screenoff", false); - if(screenoff) { - if(!ProfileManager.getLastConnectedVpn().mPersistTun) + if (screenOff) { + if (!ProfileManager.getLastConnectedVpn().mPersistTun) OpenVPN.logError(R.string.screen_nopersistenttun); screen = connectState.PENDINGDISCONNECT; fillTrafficData(); - if (network == connectState.DISCONNECTED) + if (network == connectState.DISCONNECTED || userpause == 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(); - - } + boolean connected = shouldBeConnected(); screen = connectState.SHOULDBECONNECTED; + /* should be connected has changed because the screen is on now, connect the VPN */ + if (shouldBeConnected() != connected) + mManagement.resume(); + else + /*Update the reason why we are still paused */ + mManagement.pause(getPauseReason()); + } } + private void fillTrafficData() { trafficdata.add(new Datapoint(System.currentTimeMillis(), TRAFFIC_LIMIT)); } @@ -122,18 +144,18 @@ public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountL String netstatestring; - if(networkInfo==null) { + if (networkInfo == null) { netstatestring = "not connected"; - } else { + } else { String subtype = networkInfo.getSubtypeName(); - if(subtype==null) + if (subtype == null) subtype = ""; String extrainfo = networkInfo.getExtraInfo(); - if(extrainfo==null) - extrainfo=""; + if (extrainfo == null) + extrainfo = ""; /* - if(networkInfo.getType()==android.net.ConnectivityManager.TYPE_WIFI) { + if(networkInfo.getType()==android.net.ConnectivityManager.TYPE_WIFI) { WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); WifiInfo wifiinfo = wifiMgr.getConnectionInfo(); extrainfo+=wifiinfo.getBSSID(); @@ -142,52 +164,71 @@ public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountL }*/ - - netstatestring = String.format("%2$s %4$s to %1$s %3$s",networkInfo.getTypeName(), - networkInfo.getDetailedState(),extrainfo,subtype ); + 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) { + if (networkInfo != null && networkInfo.getState() == State.CONNECTED) { int newnet = networkInfo.getType(); network = connectState.SHOULDBECONNECTED; - if(sendusr1 && lastNetwork!=newnet) { + 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(); + if (shouldBeConnected()) { + if (lastNetwork == -1) { + mManagement.resume(); + } else { + mManagement.reconnect(); + } } lastNetwork = newnet; } - } else if (networkInfo==null) { + } else if (networkInfo == null) { // Not connected, stop openvpn, set last connected network to no network - lastNetwork=-1; - if(sendusr1) { - mManangement.pause(); + lastNetwork = -1; + if (sendusr1) { network = connectState.DISCONNECTED; - // Set screen state to be disconnected if it want to disconnect + // Set screen state to be disconnected if disconnect pending if (screen == connectState.PENDINGDISCONNECT) screen = connectState.DISCONNECTED; + + mManagement.pause(getPauseReason()); } } - if(!netstatestring.equals(lastStateMsg)) + if (!netstatestring.equals(lastStateMsg)) OpenVPN.logInfo(R.string.netstatus, netstatestring); - lastStateMsg=netstatestring; + lastStateMsg = netstatestring; + + } + + public boolean isUserPaused() { + return userpause == connectState.DISCONNECTED; + } + + private boolean shouldBeConnected() { + return (screen == connectState.SHOULDBECONNECTED && userpause == connectState.SHOULDBECONNECTED && + network == connectState.SHOULDBECONNECTED); + } + + private pauseReason getPauseReason() { + if (userpause == connectState.DISCONNECTED) + return pauseReason.userPause; + + if (screen == connectState.DISCONNECTED) + return pauseReason.screenOff; + return pauseReason.noNetwork; } private NetworkInfo getCurrentNetworkInfo(Context context) { - ConnectivityManager conn = (ConnectivityManager) + ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); return conn.getActiveNetworkInfo(); diff --git a/src/de/blinkt/openvpn/core/OpenVPN.java b/src/de/blinkt/openvpn/core/OpenVPN.java index 450a13ea..66d985bd 100644 --- a/src/de/blinkt/openvpn/core/OpenVPN.java +++ b/src/de/blinkt/openvpn/core/OpenVPN.java @@ -41,21 +41,17 @@ public class OpenVPN { - public enum ConnectionStatus { - LEVEL_NONETWORK (3), - LEVEL_NOTCONNECTED (4), - LEVEL_AUTH_FAILED (5), - LEVEL_WAITING_FOR_USER_INPUT (6), - LEVEL_CONNECTING_SERVER_REPLIED ( 1), - LEVEL_CONNECTING_NO_SERVER_REPLY_YET (2), - LEVEL_CONNECTED (0), UNKNOWN_LEVEL(-1); - - private final int level; - - ConnectionStatus(int level){ - this.level = level; - } - } + public enum ConnectionStatus { + LEVEL_CONNECTED, + LEVEL_VPNPAUSED, + LEVEL_CONNECTING_SERVER_REPLIED, + LEVEL_CONNECTING_NO_SERVER_REPLY_YET, + LEVEL_NONETWORK, + LEVEL_NOTCONNECTED, + LEVEL_AUTH_FAILED, + LEVEL_WAITING_FOR_USER_INPUT, + UNKNOWN_LEVEL + } public static final byte[] officalkey = {-58, -42, -44, -106, 90, -88, -87, -88, -52, -124, 84, 117, 66, 79, -112, -111, -46, 86, -37, 109}; public static final byte[] officaldebugkey = {-99, -69, 45, 71, 114, -116, 82, 66, -99, -122, 50, -70, -56, -111, 98, -35, -65, 105, 82, 43}; @@ -305,7 +301,22 @@ public class OpenVPN { } - private static ConnectionStatus getLevel(String state){ + public static void updateStatePause(OpenVPNManagement.pauseReason pauseReason) { + switch (pauseReason) { + case noNetwork: + OpenVPN.updateStateString("NONETWORK", "", R.string.state_nonetwork, ConnectionStatus.LEVEL_NONETWORK); + break; + case screenOff: + OpenVPN.updateStateString("SCREENOFF", "", R.string.state_screenoff, ConnectionStatus.LEVEL_VPNPAUSED); + break; + case userPause: + OpenVPN.updateStateString("USERPAUSE", "", R.string.state_userpause, ConnectionStatus.LEVEL_VPNPAUSED); + break; + } + + } + + private static ConnectionStatus getLevel(String state){ String[] noreplyet = {"CONNECTING","WAIT", "RECONNECTING", "RESOLVE", "TCP_CONNECT"}; String[] reply = {"AUTH","GET_CONFIG","ASSIGN_IP","ADD_ROUTES"}; String[] connected = {"CONNECTED"}; diff --git a/src/de/blinkt/openvpn/core/OpenVPNManagement.java b/src/de/blinkt/openvpn/core/OpenVPNManagement.java index 5b8fc074..ce8d38c2 100644 --- a/src/de/blinkt/openvpn/core/OpenVPNManagement.java +++ b/src/de/blinkt/openvpn/core/OpenVPNManagement.java @@ -1,11 +1,17 @@ package de.blinkt.openvpn.core; public interface OpenVPNManagement { - int mBytecountinterval=2; + enum pauseReason { + noNetwork, + userPause, + screenOff + } + + int mBytecountInterval =2; void reconnect(); - void pause(); + void pause(pauseReason reason); void resume(); diff --git a/src/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/core/OpenVpnManagementThread.java index 13bebc8a..c4b4f379 100644 --- a/src/de/blinkt/openvpn/core/OpenVpnManagementThread.java +++ b/src/de/blinkt/openvpn/core/OpenVpnManagementThread.java @@ -1,16 +1,5 @@ package de.blinkt.openvpn.core; -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.LinkedList; -import java.util.Locale; -import java.util.Vector; - import android.content.Context; import android.content.SharedPreferences; import android.net.LocalServerSocket; @@ -23,6 +12,18 @@ import de.blinkt.openvpn.R; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.OpenVPN.ConnectionStatus; +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.Collections; +import java.util.LinkedList; +import java.util.Locale; +import java.util.Vector; + public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { private static final String TAG = "openvpn"; @@ -33,11 +34,13 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { private LocalServerSocket mServerSocket; private boolean mReleaseHold=true; private boolean mWaitingForRelease=false; - private long mLastHoldRelease=0; + private long mLastHoldRelease=0; private static Vector active=new Vector(); private LocalSocket mServerSocketLocal; + private pauseReason lastPauseReason = pauseReason.noNetwork; + public OpenVpnManagementThread(VpnProfile profile, OpenVpnService openVpnService) { mProfile = profile; mOpenVPNService = openVpnService; @@ -50,6 +53,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { } + public boolean openManagementInterface(Context c) { // Could take a while to open connection int tries=8; @@ -66,7 +70,9 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { } catch (IOException e) { // wait 300 ms before retrying try { Thread.sleep(300); - } catch (InterruptedException e1) {} + } catch (InterruptedException e1) { + e1.printStackTrace(); + } } tries--; @@ -133,11 +139,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { e.printStackTrace(); } if(fds!=null){ - - for (FileDescriptor fd : fds) { - - mFDList.add(fd); - } + Collections.addAll(mFDList, fds); } String input = new String(buffer,0,numbytesread,"UTF-8"); @@ -157,7 +159,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { //! Hack O Rama 2000! private void protectFileDescriptor(FileDescriptor fd) { - Exception exp=null; + Exception exp; try { Method getInt = FileDescriptor.class.getDeclaredMethod("getInt$"); int fdint = (Integer) getInt.invoke(fd); @@ -181,11 +183,10 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { } catch (NullPointerException e) { exp =e; } - if(exp!=null) { - exp.printStackTrace(); - Log.d("Openvpn", "Failed to retrieve fd from socket: " + fd); - OpenVPN.logMessage(0, "", "Failed to retrieve fd from socket: " + exp.getLocalizedMessage()); - } + + exp.printStackTrace(); + Log.d("Openvpn", "Failed to retrieve fd from socket: " + fd); + OpenVPN.logMessage(0, "", "Failed to retrieve fd from socket: " + exp.getLocalizedMessage()); } private String processInput(String pendingInput) { @@ -214,6 +215,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { if(cmd.equals("INFO")) { // Ignore greeting from mgmt //logStatusMessage(command); + ; }else if (cmd.equals("PASSWORD")) { processPWCommand(argument); } else if (cmd.equals("HOLD")) { @@ -239,6 +241,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { Log.i(TAG, "Got unrecognized command" + command); } } else if (command.startsWith("SUCCESS:")) { + ; // ignore } else { Log.i(TAG, "Got unrecognized line from managment" + command); @@ -250,20 +253,25 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { releaseHoldCmd(); } else { mWaitingForRelease=true; - OpenVPN.updateStateString("NONETWORK", "",R.string.state_nonetwork,ConnectionStatus.LEVEL_NONETWORK); + + OpenVPN.updateStatePause(lastPauseReason); + + } } private void releaseHoldCmd() { if ((System.currentTimeMillis()- mLastHoldRelease) < 5000) { try { Thread.sleep(3000); - } catch (InterruptedException e) {} + } catch (InterruptedException e) { + e.printStackTrace(); + } } mWaitingForRelease=false; mLastHoldRelease = System.currentTimeMillis(); managmentCommand("hold release\n"); - managmentCommand("bytecount " + mBytecountinterval + "\n"); + managmentCommand("bytecount " + mBytecountInterval + "\n"); managmentCommand("state on\n"); } @@ -366,7 +374,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { } private boolean sendTunFD (String needed, String extra) { - Exception exp = null; + Exception exp; if(!extra.equals("tun")) { // We only support tun String errmsg = String.format("Devicetype %s requested, but only tun is possible with the Android API, sorry!",extra); @@ -413,11 +421,10 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { } catch (IOException e) { exp =e; } - if(exp!=null) { - OpenVPN.logMessage(0,"", "Could not send fd over socket:" + exp.getLocalizedMessage()); - exp.printStackTrace(); - } - return false; + OpenVPN.logMessage(0, "", "Could not send fd over socket:" + exp.getLocalizedMessage()); + exp.printStackTrace(); + + return false; } private void processPWCommand(String argument) { @@ -485,8 +492,13 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { public void signalusr1() { mReleaseHold=false; + if(!mWaitingForRelease) managmentCommand("signal SIGUSR1\n"); + else + // If signalusr1 is called update the state string + // if there is another for stopping + OpenVPN.updateStatePause(lastPauseReason); } public void reconnect() { @@ -503,13 +515,16 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { } @Override - public void pause() { + public void pause (pauseReason reason) { + lastPauseReason = reason; signalusr1(); } @Override public void resume() { releaseHold(); + /* Reset the reason why we are disconnected */ + lastPauseReason = pauseReason.noNetwork; } @Override diff --git a/src/de/blinkt/openvpn/core/OpenVpnService.java b/src/de/blinkt/openvpn/core/OpenVpnService.java index 74ae7245..230ddbaa 100644 --- a/src/de/blinkt/openvpn/core/OpenVpnService.java +++ b/src/de/blinkt/openvpn/core/OpenVpnService.java @@ -9,7 +9,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; -import android.net.*; +import android.net.ConnectivityManager; +import android.net.VpnService; import android.os.*; import android.os.Handler.Callback; import android.preference.PreferenceManager; @@ -33,8 +34,12 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac 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"; + public static final String DISCONNECT_VPN = "de.blinkt.openvpn.DISCONNECT_VPN"; + private static final String PAUSE_VPN = "de.blinkt.openvpn.PAUSE_VPN"; + private static final String RESUME_VPN = "de.blinkt.openvpn.RESUME_VPN"; - private Thread mProcessThread=null; + + private Thread mProcessThread=null; private final Vector mDnslist=new Vector(); @@ -60,8 +65,6 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac private static final int OPENVPN_STATUS = 1; - public static final int PROTECT_FD = 0; - private static boolean mNotificationAlwaysVisible =false; private final IBinder mBinder = new LocalBinder(); @@ -111,12 +114,12 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac } } - private void showNotification(String msg, String tickerText, boolean lowpriority, long when, ConnectionStatus level) { + private void showNotification(String msg, String tickerText, boolean lowpriority, long when, ConnectionStatus status) { String ns = Context.NOTIFICATION_SERVICE; NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns); - int icon = getIconByLevel(level); + int icon = getIconByConnectionStatus(status); android.app.Notification.Builder nbuilder = new Notification.Builder(this); @@ -131,6 +134,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac nbuilder.setContentIntent(getLogPendingIntent()); nbuilder.setSmallIcon(icon); + if(when !=0) nbuilder.setWhen(when); @@ -148,7 +152,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac startForeground(OPENVPN_STATUS, notification); } - private int getIconByLevel(ConnectionStatus level) { + private int getIconByConnectionStatus(ConnectionStatus level) { switch (level) { case LEVEL_CONNECTED: case UNKNOWN_LEVEL: @@ -162,6 +166,8 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac return R.drawable.ic_stat_vpn_outline; case LEVEL_CONNECTING_SERVER_REPLIED: return R.drawable.ic_stat_vpn_empty_halo; + case LEVEL_VPNPAUSED: + return android.R.drawable.ic_media_pause; default: return R.drawable.ic_stat_vpn; @@ -181,17 +187,39 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac Method setUsesChronometer = nbuilder.getClass().getMethod("setUsesChronometer", boolean.class); setUsesChronometer.invoke(nbuilder,true); - /* PendingIntent cancelconnet=null; - - nbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, - getString(R.string.cancel_connection),cancelconnet); */ } - //ignore exception + Intent disconnectVPN = new Intent(this,LogWindow.class); + disconnectVPN.setAction(DISCONNECT_VPN); + PendingIntent disconnectPendingIntent = PendingIntent.getActivity(this, 0, disconnectVPN, 0); + + nbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, + getString(R.string.cancel_connection),disconnectPendingIntent); + + Intent pauseVPN = new Intent(this,OpenVpnService.class); + if (mDeviceStateReceiver == null || !mDeviceStateReceiver.isUserPaused()) { + pauseVPN.setAction(PAUSE_VPN); + PendingIntent pauseVPNPending = PendingIntent.getService(this,0,pauseVPN,0); + nbuilder.addAction(android.R.drawable.ic_media_pause, + getString(R.string.pauseVPN), pauseVPNPending); + + } else { + pauseVPN.setAction(RESUME_VPN); + PendingIntent resumeVPNPending = PendingIntent.getService(this,0,pauseVPN,0); + nbuilder.addAction(android.R.drawable.ic_media_play, + getString(R.string.resumevpn), resumeVPNPending); + } + + + //ignore exception } catch (NoSuchMethodException nsm) { + nsm.printStackTrace(); } catch (IllegalArgumentException e) { + e.printStackTrace(); } catch (IllegalAccessException e) { + e.printStackTrace(); } catch (InvocationTargetException e) { + e.printStackTrace(); } } @@ -241,7 +269,22 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac OpenVPN.addStateListener(this); OpenVPN.addByteCountListener(this); - if(intent != null && intent.getAction() !=null &&intent.getAction().equals(START_SERVICE)) + if(intent != null && intent.getAction() !=null &&intent.getAction().equals(PAUSE_VPN)) + { + if(mDeviceStateReceiver!=null) + mDeviceStateReceiver.userPause(true); + return START_NOT_STICKY; + } + + if(intent != null && intent.getAction() !=null &&intent.getAction().equals(RESUME_VPN)) + { + if(mDeviceStateReceiver!=null) + mDeviceStateReceiver.userPause(false); + return START_NOT_STICKY; + } + + + 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; @@ -566,9 +609,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac if(mDisplayBytecount) { String netstat = String.format(getString(R.string.statusline_bytecount), humanReadableByteCount(in, false), - humanReadableByteCount(diffin/ OpenVPNManagement.mBytecountinterval, true), + humanReadableByteCount(diffin/ OpenVPNManagement.mBytecountInterval, true), humanReadableByteCount(out, false), - humanReadableByteCount(diffout/ OpenVPNManagement.mBytecountinterval, true)); + humanReadableByteCount(diffout/ OpenVPNManagement.mBytecountInterval, true)); boolean lowpriority = !mNotificationAlwaysVisible; showNotification(netstat,null,lowpriority,mConnecttime, LEVEL_CONNECTED); -- cgit v1.2.3