From 32e00cb1dc377672b31c8eb8b0d78ff38aec4023 Mon Sep 17 00:00:00 2001
From: "martin.byrenheid"
 <martin.byrenheid@5a230232-f31e-4839-b85c-661838634aa0>
Date: Mon, 16 Apr 2018 17:29:52 +0000
Subject: [PATCH] Integrated connectivity management of vpn lib

---
 app/src/main/AndroidManifest.xml              |   3 +-
 .../anon_next/android/AndroidVpnService.java  |   4 +-
 .../service/foreground/ForegroundService.java |  66 ++++---
 .../service/gui/AndroidGUIInterface.java      | 168 ++++++++----------
 .../AndroidConnectivityMonitor.java           |  63 +++++++
 .../AndroidConnectivityMonitorFactory.java    |  35 ++++
 .../android/ui/VPNConnectedActivity.java      |   3 +-
 .../android/ui/main/AnonFragment.java         | 101 ++++++-----
 .../android/ui/main/MainActivity.java         |  83 +++------
 app/src/main/res/values/colors.xml            |   3 +-
 app/src/main/res/values/strings.xml           |   6 +-
 11 files changed, 315 insertions(+), 220 deletions(-)
 create mode 100644 app/src/main/java/anonvpn/anon_next/android/service/networking/AndroidConnectivityMonitor.java
 create mode 100644 app/src/main/java/anonvpn/anon_next/android/service/networking/AndroidConnectivityMonitorFactory.java

diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index bf393ef..7910f02 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -20,8 +20,7 @@
       tools:node="remove"/>
 
     <uses-permission
-      android:name="android.permission.ACCESS_NETWORK_STATE"
-      tools:node="remove"/>
+      android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission
       android:name="android.permission.ACCESS_WIFI_STATE"
       tools:node="remove"/>
diff --git a/app/src/main/java/anonvpn/anon_next/android/AndroidVpnService.java b/app/src/main/java/anonvpn/anon_next/android/AndroidVpnService.java
index 866ce15..7d03f19 100644
--- a/app/src/main/java/anonvpn/anon_next/android/AndroidVpnService.java
+++ b/app/src/main/java/anonvpn/anon_next/android/AndroidVpnService.java
@@ -17,6 +17,7 @@ import java.io.IOException;
 
 import anonvpn.anon_next.android.service.gui.AndroidGUIFactory;
 import anonvpn.anon_next.android.service.gui.AndroidGUIInterface;
+import anonvpn.anon_next.android.service.networking.AndroidConnectivityMonitorFactory;
 import anonvpn.anon_next.android.service.networking.AndroidNetworkFactory;
 import anonvpn.anon_next.android.service.networking.AndroidProtectedSocketFactory;
 import anonvpn.anon_next.android.service.persistence.AndroidPersistenceFactory;
@@ -80,10 +81,11 @@ public class AndroidVpnService extends VpnService
 						AndroidProtectedSocketFactory mixSocketFactory = new AndroidProtectedSocketFactory(this);
 						AndroidGUIFactory guiFactory = new AndroidGUIFactory(this);
 
+						AndroidConnectivityMonitorFactory connMonFactory = new AndroidConnectivityMonitorFactory(getApplicationContext());
 						Log.e("AndroidVPNService", "Starting core service!");
 						AndroidResourceLoaderHelper resourecLoaderHelper = new AndroidResourceLoaderHelper(getAssets());
 						AndroidLog logger = new AndroidLog();
-						anonvpnService = new ANONVPNService(mNetworkFactory, persistenceFactory, guiFactory, mixSocketFactory, resourecLoaderHelper, logger);
+						anonvpnService = new ANONVPNService(mNetworkFactory, persistenceFactory, guiFactory, connMonFactory, mixSocketFactory, resourecLoaderHelper, logger);
 					}
 
 				// service running until it is explicitly stopped,return sticky.
diff --git a/app/src/main/java/anonvpn/anon_next/android/service/foreground/ForegroundService.java b/app/src/main/java/anonvpn/anon_next/android/service/foreground/ForegroundService.java
index eb3d3fd..ef410d9 100644
--- a/app/src/main/java/anonvpn/anon_next/android/service/foreground/ForegroundService.java
+++ b/app/src/main/java/anonvpn/anon_next/android/service/foreground/ForegroundService.java
@@ -18,6 +18,7 @@ import anonvpn.anon_next.android.R;
 import anonvpn.anon_next.android.service.gui.AndroidGUIInterface;
 import anonvpn.anon_next.android.ui.main.MainActivity;
 import anonvpn.anon_next.core.gui.IVPNInterface;
+import anonvpn.anon_next.core.gui.VPNState;
 
 
 public class ForegroundService extends Service
@@ -28,7 +29,7 @@ public class ForegroundService extends Service
 		String cascade_location = "";
 		String cascade_name = "";
 		IVPNInterface.RxTx m_RxTx= IVPNInterface.RxTx.ALL_ZERO;
-		int conn_state = 0;
+		VPNState conn_state = VPNState.DISABLED;
 
 		private final int TRAFFIC_STATS_DELAY = 3000;
 		private final Handler mTrafficStatisticsHandler = new Handler();
@@ -97,7 +98,7 @@ public class ForegroundService extends Service
 						cascade_ip = intent.getStringExtra("ip");
 						cascade_location = intent.getStringExtra("location");
 						cascade_name = intent.getStringExtra("name");
-						conn_state = intent.getIntExtra("conn_state", 0);
+						conn_state = VPNState.valueOf(intent.getStringExtra("conn_state"));
 					}
 				showNotification();
 				return START_STICKY;
@@ -125,39 +126,52 @@ public class ForegroundService extends Service
 			{
 
 				NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this).setContentTitle(getString(R.string.foregroundservice_title));
-				if (conn_state == 0)            // Not connected to VPN
-					{
+				switch (conn_state) {
+
+					case DISABLED:
 						mBuilder.setSmallIcon(getIconError()).setContentText(getString(R.string.foregroundservice_desc_vpn_disabled));
 
 						if (mVPNConnection != null)
-							{
-								disconnectVPNService();
-							}
-					}
-				else if (conn_state == 1)     // Not connected to cascade
-					{
+						{
+							disconnectVPNService();
+						}
+						break;
+
+					case WAITING:
+
 						mBuilder.setSmallIcon(getIconWarning()).setContentText(getString(R.string.foregroundservice_desc_cascade_error));
 
-					}
-				else if (conn_state == 2)     // Connection successfully established
-					{
+						break;
+
+					case CONNECTED:
 						String message = getString(R.string.foregroundservice_desc_active_name) +
-										cascade_name +  getString(R.string.foregroundservice_desc_active_location) +
-										cascade_location +  getString(R.string.foregroundservice_desc_active_ip) +
-										cascade_ip +  getString(R.string.foregroundservice_desc_active_Rx)  +
-										Util.formatBytesValueWithUnit(m_RxTx.m_RxTotal)+"\n" +
-									getString(R.string.foregroundservice_desc_active_Tx) + Util.formatBytesValueWithUnit(m_RxTx.m_TxTotal) ;
+								cascade_name +  getString(R.string.foregroundservice_desc_active_location) +
+								cascade_location +  getString(R.string.foregroundservice_desc_active_ip) +
+								cascade_ip +  getString(R.string.foregroundservice_desc_active_Rx)  +
+								Util.formatBytesValueWithUnit(m_RxTx.m_RxTotal)+"\n" +
+								getString(R.string.foregroundservice_desc_active_Tx) + Util.formatBytesValueWithUnit(m_RxTx.m_TxTotal) ;
 						mBuilder.setSmallIcon(getIconOK()).setStyle(new NotificationCompat.BigTextStyle().bigText(message)).setContentText(message);
 
 						if (mVPNConnection == null)
-							{
-								connectToVPNService();
-							}
-					}
-				else
-					{
-						throw new RuntimeException("Unexpected conn_state: " + conn_state);
-					}
+						{
+							connectToVPNService();
+						}
+						break;
+
+					case CONNECTING:
+
+						mBuilder.setSmallIcon(getIconWarning()).setContentText(getString(R.string.foregroundservice_desc_connecting));
+
+						break;
+
+					case DISCONNECTED:
+
+						mBuilder.setSmallIcon(getIconWarning()).setContentText(getString(R.string.foregroundservice_desc_network));
+
+						break;
+
+				}
+
 				// Creates an explicit intent for an Activity in your app
 				Intent resultIntent = new Intent(this, MainActivity.class);
 
diff --git a/app/src/main/java/anonvpn/anon_next/android/service/gui/AndroidGUIInterface.java b/app/src/main/java/anonvpn/anon_next/android/service/gui/AndroidGUIInterface.java
index e71aa19..4007945 100644
--- a/app/src/main/java/anonvpn/anon_next/android/service/gui/AndroidGUIInterface.java
+++ b/app/src/main/java/anonvpn/anon_next/android/service/gui/AndroidGUIInterface.java
@@ -6,13 +6,16 @@ import android.util.Log;
 
 import java.util.Hashtable;
 
+import anon.crypto.SignatureVerifier;
 import anon.infoservice.MixCascade;
+import anon.infoservice.MixInfo;
 import anon.util.CountryMapper;
 import anonvpn.anon_next.android.AndroidVpnService;
 import anonvpn.anon_next.android.service.foreground.ForegroundService;
 import anonvpn.anon_next.android.ui.main.MainActivity;
 import anonvpn.anon_next.core.InfoService;
 import anonvpn.anon_next.core.gui.IVPNInterface;
+import anonvpn.anon_next.core.gui.VPNState;
 import anonvpn.anon_next.core.notification.Event;
 import anonvpn.anon_next.core.notification.NotificationDispatcher;
 import anonvpn.anon_next.core.notification.Observer;
@@ -28,16 +31,13 @@ public class AndroidGUIInterface extends Binder implements IVPNInterface, Observ
 		private final InfoService mInfoService;
 		private static final String LOGTAG = "AndroidGUIInterface";
 
+		private VPNState mVPNState = VPNState.DISABLED;
+
 		private long m_lastSentBytes = 0;
 		private long m_lastReceivedBytes = 0;
 		private long m_lastRxTxUpdate = 0;
 
 
-		private MixCascade mChosenCascade = null;
-		private boolean mConnected = false;
-		//private final RxTx m_RxTx = new RxTx();
-
-
 		public AndroidGUIInterface(AndroidVpnService vpnService, NotificationDispatcher dispatcher, IConfig config, InfoService infoService)
 			{
 				this.mVpnService = vpnService;
@@ -45,10 +45,14 @@ public class AndroidGUIInterface extends Binder implements IVPNInterface, Observ
 				this.mConfig = config;
 				this.mInfoService = infoService;
 
+				mDispatcher.subscribe(Event.CASCADE_CONNECTING, this);
 				mDispatcher.subscribe(Event.CASCADE_CONNECTED, this);
 				mDispatcher.subscribe(Event.CASCADE_DISCONNECTED, this);
+				mDispatcher.subscribe(Event.CASCADE_LOST, this);
+
+				// Simplifies notification of foreground service and main activity
+				// after the VPN has been disabled
 				mDispatcher.subscribe(Event.VPN_DISABLED, this);
-				mDispatcher.subscribe(Event.VPN_ENABLED, this);
 
 				updateFGService();
 			}
@@ -73,14 +77,6 @@ public class AndroidGUIInterface extends Binder implements IVPNInterface, Observ
 				return rxtx;
 			}
 
-
-		@Override
-		public boolean isConnectedToCascade()
-			{
-				// TODO: Replace with actual communication with service
-				return mConnected;
-			}
-
 		public boolean hasChosenCascade()
 			{
 				return mConfig.getChosenMixCascade() != null;
@@ -137,115 +133,109 @@ public class AndroidGUIInterface extends Binder implements IVPNInterface, Observ
 		public void enableTunneling()
 			{
 				mVpnService.startTunnelingDevice();
-				mDispatcher.notify(Event.VPN_ENABLED);
+				mDispatcher.notifyAsync(Event.VPN_ENABLED);
 			}
 
 		@Override
 		public void disableTunneling()
 			{
 				mVpnService.stopTunnelingDevice();
-				mDispatcher.notify(Event.VPN_DISABLED);
+				mDispatcher.notifyAsync(Event.VPN_DISABLED);
 			}
 
 		@Override
-		public boolean tunnelingEnabled()
-			{
-				return mVpnService.tunnelingEnabled();
-			}
+		public anonvpn.anon_next.core.gui.VPNState getServiceState() {
+			return mVPNState;
+		}
+
+		private void notifyMainActivity() {
+			Intent notificationIntent = null;
+			notificationIntent = new Intent(mVpnService.getApplicationContext(), MainActivity.class);
+			notificationIntent.putExtra("type", "notification");
+			notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+			mVpnService.startActivity(notificationIntent);
+		}
 
 		@Override
 		public void notify(Event event)
 			{
-				// TODO: SEND INTENTS TO MAINACTIVITY HERE
-				if (event == Event.CASCADE_CONNECTED)
-					{
+				switch(event) {
+
+					case VPN_DISABLED:
+						mVPNState = VPNState.DISABLED;
+						break;
+
+					case CASCADE_CONNECTING:
+						mVPNState = VPNState.CONNECTING;
+						break;
+
+					case CASCADE_CONNECTED:
 						Log.i(LOGTAG, "Event received: Cascade connected.");
-						mConnected = true;
-						Intent startIntent = new Intent(mVpnService.getApplicationContext(), MainActivity.class);
-						startIntent.putExtra("FragmentID", MainActivity.FRAGMENTID_ANONYMITY);
-						startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-						mVpnService.startActivity(startIntent);
+						mVPNState = VPNState.CONNECTED;
+						break;
 
-					}
-				else if (event == Event.CASCADE_DISCONNECTED)
-					{
+					case CASCADE_DISCONNECTED:
 						Log.i(LOGTAG, "Event received: Cascade disconnected.");
-						mConnected = false;
+						mVPNState = VPNState.DISCONNECTED;
+						break;
 
-						Intent startIntent = new Intent(mVpnService.getApplicationContext(), MainActivity.class);
-						startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-						mVpnService.startActivity(startIntent);
+					case CASCADE_LOST:
+						mVPNState = VPNState.WAITING;
+						break;
 
-					}
-				else if (event == Event.VPN_ENABLED)
-					{
-						Log.i(LOGTAG, "Event received: VPN enabled.");
+					default:
 
-					}
-				else if (event == Event.VPN_DISABLED)
-					{
-						Log.i(LOGTAG, "Event received: VPN disabled.");
-
-					}
-				else
-					{
 						Log.e(LOGTAG, "Unexpected event!");
 						throw new RuntimeException();
-					}
+				}
+
+				notifyMainActivity();
 				updateFGService();
-				//todo: intent --> MainActivity->AnonFragment->updateStatus()
 			}
 
 		private void updateFGService()
 			{
 				Log.e("AndroidVPNMainActivity", "Preparing ForegroundService!");
-//			mSharedPreferences.edit().putBoolean("FGServiceStarted", true).apply();
 				Intent startIntent = new Intent(mVpnService.getApplicationContext(), ForegroundService.class);
 				try
 					{
-						int conn_state;
-						if (!mVpnService.tunnelingEnabled())
-							{
-								conn_state = 0;
-							}
-						else if (!mConnected)
-							{
-								conn_state = 1;
-							}
-						else
+
+						MixCascade cascade = getChosenCascade();
+						String ip = "";
+						String location = "";
+						String name = "";
+						if (cascade != null)
 							{
-								conn_state = 2;
-								MixCascade cascade = getChosenCascade();
-								String ip = "";
-								String location = "";
-								String name = "";
-								if (cascade != null)
+								try
 									{
-										try
-											{
-												int nrOfMixes = cascade.getNumberOfMixes();
-												ip = cascade.getMixInfo(nrOfMixes - 1).getFirstHostName();
-												String countryCode = cascade.getMixInfo(nrOfMixes - 1).getServiceLocation().getCountryCode();
-												CountryMapper c = new CountryMapper(countryCode);
-												location = c.toString();
-												name = getChosenCascade().getName();
-											}
-										catch (Exception e)
-											{
-												e.printStackTrace();
-											}
+										int nrOfMixes = cascade.getNumberOfMixes();
+										MixInfo cascadeInfo = cascade.getMixInfo(nrOfMixes - 1);
+
+										String countryCode = "DE";
+										ip = "Unknown";
+										if (cascadeInfo != null) {
+											ip = cascadeInfo.getFirstHostName();
+											countryCode = cascadeInfo.getServiceLocation().getCountryCode();
+										}
+										CountryMapper c = new CountryMapper(countryCode);
+										location = c.toString();
+										name = getChosenCascade().getName();
+									}
+								catch (Exception e)
+									{
+										e.printStackTrace();
 									}
-								startIntent.putExtra("ip", ip);
-								startIntent.putExtra("location", location);
-								startIntent.putExtra("name", name);
-
-								startIntent.putExtra("conn_state", conn_state);
 							}
-					}
-				catch (Exception e)
-					{
-						e.printStackTrace();
-					}
+						startIntent.putExtra("ip", ip);
+						startIntent.putExtra("location", location);
+						startIntent.putExtra("name", name);
+
+						startIntent.putExtra("conn_state", mVPNState.toString());
+				}
+			catch (Exception e)
+				{
+					e.printStackTrace();
+				}
 				mVpnService.startService(startIntent);
 			}
 
diff --git a/app/src/main/java/anonvpn/anon_next/android/service/networking/AndroidConnectivityMonitor.java b/app/src/main/java/anonvpn/anon_next/android/service/networking/AndroidConnectivityMonitor.java
new file mode 100644
index 0000000..818fa9c
--- /dev/null
+++ b/app/src/main/java/anonvpn/anon_next/android/service/networking/AndroidConnectivityMonitor.java
@@ -0,0 +1,63 @@
+package anonvpn.anon_next.android.service.networking;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+
+import anonvpn.anon_next.core.networking.IConnectivityMonitor;
+import anonvpn.anon_next.core.notification.Event;
+import anonvpn.anon_next.core.notification.NotificationDispatcher;
+
+/**
+ * Created by martin on 03.04.18.
+ */
+
+public class AndroidConnectivityMonitor extends BroadcastReceiver implements IConnectivityMonitor {
+
+    private final NotificationDispatcher mNotification;
+    private final ConnectivityManager mConnectivityManager;
+    private boolean mConnected = false;
+
+    public AndroidConnectivityMonitor(NotificationDispatcher dispatcher, ConnectivityManager connManager) {
+
+        mNotification = dispatcher;
+
+        mConnectivityManager = connManager;
+
+        NetworkInfo activeNetwork = mConnectivityManager.getActiveNetworkInfo();
+        mConnected = activeNetwork != null &&
+                activeNetwork.isConnectedOrConnecting();
+
+
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+
+        NetworkInfo activeNetwork = mConnectivityManager.getActiveNetworkInfo();
+
+        boolean connected = activeNetwork != null &&
+                activeNetwork.isConnectedOrConnecting();
+
+        if (! mConnected && connected) {
+            mConnected = connected;
+            System.out.println("Network connected!");
+            mNotification.notify(Event.NETWORK_CONNECTED);
+
+        }
+
+        if (mConnected && ! connected) {
+            mConnected = connected;
+            System.out.println("Network disconnected!");
+            mNotification.notify(Event.NETWORK_DISCONNECTED);
+
+        }
+    }
+
+    @Override
+    public boolean deviceIsConnected() {
+        return mConnected;
+    }
+}
diff --git a/app/src/main/java/anonvpn/anon_next/android/service/networking/AndroidConnectivityMonitorFactory.java b/app/src/main/java/anonvpn/anon_next/android/service/networking/AndroidConnectivityMonitorFactory.java
new file mode 100644
index 0000000..3666786
--- /dev/null
+++ b/app/src/main/java/anonvpn/anon_next/android/service/networking/AndroidConnectivityMonitorFactory.java
@@ -0,0 +1,35 @@
+package anonvpn.anon_next.android.service.networking;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+
+import anonvpn.anon_next.core.networking.IConnectivityMonitor;
+import anonvpn.anon_next.core.networking.IConnectivityMonitorFactory;
+import anonvpn.anon_next.core.notification.NotificationDispatcher;
+
+/**
+ * Created by martin on 06.04.18.
+ */
+
+public class AndroidConnectivityMonitorFactory implements IConnectivityMonitorFactory {
+
+    private final ConnectivityManager mConnectivityManager;
+    private final Context mAppContext;
+
+    public AndroidConnectivityMonitorFactory(Context context) {
+        mAppContext = context;
+        ConnectivityManager cm =
+                (ConnectivityManager)mAppContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mConnectivityManager = cm;
+    }
+
+    @Override
+    public IConnectivityMonitor getConnectivityMonitor(NotificationDispatcher notificationDispatcher) {
+        AndroidConnectivityMonitor result = new AndroidConnectivityMonitor(notificationDispatcher, mConnectivityManager);
+        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+        mAppContext.registerReceiver(result, filter);
+        return result;
+    }
+}
diff --git a/app/src/main/java/anonvpn/anon_next/android/ui/VPNConnectedActivity.java b/app/src/main/java/anonvpn/anon_next/android/ui/VPNConnectedActivity.java
index 4399041..13b0c7d 100644
--- a/app/src/main/java/anonvpn/anon_next/android/ui/VPNConnectedActivity.java
+++ b/app/src/main/java/anonvpn/anon_next/android/ui/VPNConnectedActivity.java
@@ -10,6 +10,7 @@ import android.util.Log;
 
 import anonvpn.anon_next.android.AndroidVpnService;
 import anonvpn.anon_next.android.service.gui.AndroidGUIInterface;
+import anonvpn.anon_next.core.gui.VPNState;
 
 /**
  * Created by martin on 8/9/17.
@@ -93,7 +94,7 @@ abstract public class VPNConnectedActivity extends AppCompatActivity
 
 		public boolean isTunnelingEnabled()
 			{
-				return (isVPNConnected() && getServiceInterface().tunnelingEnabled());
+				return (isVPNConnected() && getServiceInterface().getServiceState() != VPNState.DISABLED);
 			}
 
 		public AndroidGUIInterface getServiceInterface()
diff --git a/app/src/main/java/anonvpn/anon_next/android/ui/main/AnonFragment.java b/app/src/main/java/anonvpn/anon_next/android/ui/main/AnonFragment.java
index ca49c47..aecd279 100644
--- a/app/src/main/java/anonvpn/anon_next/android/ui/main/AnonFragment.java
+++ b/app/src/main/java/anonvpn/anon_next/android/ui/main/AnonFragment.java
@@ -22,6 +22,8 @@ import android.widget.ProgressBar;
 import android.widget.TextView;
 
 import anon.infoservice.MixCascade;
+import anon.infoservice.MixInfo;
+import anon.infoservice.ServiceLocation;
 import anon.util.CountryMapper;
 import anon.util.Util;
 import anonvpn.anon_next.android.R;
@@ -109,9 +111,7 @@ final public class AnonFragment extends Fragment
 											}
 										else
 											{
-
 												startVPNTunneling();
-												updateStatus();
 											}
 
 									}
@@ -156,7 +156,6 @@ final public class AnonFragment extends Fragment
 			{
 
 				((MainActivity) getActivity()).enableVPNTunneling();
-
 			}
 
 		private void stopVPNTunneling()
@@ -263,59 +262,73 @@ final public class AnonFragment extends Fragment
 
 		public void updateStatus()
 			{
-				MainActivity a=(MainActivity) getActivity();
-				if(a==null)
-					return;
-				if (a.isTunnelingEnabled())
-					{
 
-						Log.e("ANONFragment", "VPN is running!");
-						sw.setChecked(true);
+				MainActivity main = (MainActivity) getActivity();
 
-						// Check if the user already selected a cascade
-						if (a.getServiceInterface().isConnectedToCascade())
-							{
-								IVPNInterface.RxTx rxtx = a.getServiceInterface().getRxTx();
+				if (main != null) {
+					AndroidGUIInterface service = main.getServiceInterface();
+
+					if (service != null) {
+
+						switch (service.getServiceState()) {
+
+							case CONNECTING:
+								if (!sw.isChecked()) {
+									sw.setChecked(true);
+								}
+								m_tvStatus.setText(getContext().getString(R.string.start_state_establish));
+								m_tvStatus.setTextColor(getResources().getColor(R.color.connectivity_problem));
+								break;
+
+							case CONNECTED:
+								IVPNInterface.RxTx rxtx = service.getRxTx();
 								updateTrafficStatistics(rxtx);
-								if (!m_TrafficStatisticsTask.isScheduled )
-									{
-										m_TrafficStatisticsHandler.postDelayed(m_TrafficStatisticsTask, TRAFFIC_STATS_DELAY);
-										m_TrafficStatisticsTask.isScheduled = true;
-									}
+								if (!m_TrafficStatisticsTask.isScheduled) {
+									m_TrafficStatisticsHandler.postDelayed(m_TrafficStatisticsTask, TRAFFIC_STATS_DELAY);
+									m_TrafficStatisticsTask.isScheduled = true;
+								}
 								m_tvStatus.setText(getContext().getString(R.string.start_state_active));
 								m_tvStatus.setTextColor(getResources().getColor(R.color.connectivity_ok));
 								((TextView) m_viewContent.findViewById(R.id.anon_tv_tip)).setText("");
-								MixCascade cascade=a.getServiceInterface().getChosenCascade();
-								String countryCode = cascade.getMixInfo(cascade.getNumberOfMixes() - 1).getServiceLocation().getCountryCode();
+								MixCascade cascade = service.getChosenCascade();
+
+								MixInfo cascadeInfo = cascade.getMixInfo(cascade.getNumberOfMixes() - 1);
+								String countryCode = "DE";
+								if (cascadeInfo != null) {
+									countryCode = cascadeInfo.getServiceLocation().getCountryCode();
+								}
 								CountryMapper c = new CountryMapper(countryCode);
 								String location = c.toString();
 								m_tvLocation.setText(location);
-								
-							}
-						else
-							{
+								break;
 
-								m_tvStatus.setText(getContext().getString(R.string.start_label_noconnect));
-								m_tvStatus.setTextColor(getResources().getColor(R.color.connectivity_problem));
-								((TextView) m_viewContent.findViewById(R.id.anon_tv_tip)).setText(R.string.start_tip_choosenet);
+							case WAITING:
+								m_tvStatus.setText(getContext().getString(R.string.start_state_noservice));
+								m_tvStatus.setTextColor(getResources().getColor(R.color.connectivity_fatal));
+								break;
+
+							case DISCONNECTED:
+								m_tvStatus.setText(getContext().getString(R.string.start_state_nocon));
+								m_tvStatus.setTextColor(getResources().getColor(R.color.connectivity_fatal));
+								break;
+
+							case DISABLED:
+								Log.e("ANONFragment", "VPN is not running!");
+								sw.setChecked(false);
+
+								m_TrafficStatisticsHandler.removeCallbacks(m_TrafficStatisticsTask);
+								m_TrafficStatisticsTask.isScheduled = false;
+								updateTrafficStatistics(IVPNInterface.RxTx.ALL_ZERO);
+
+								m_tvStatus.setText(getContext().getString(R.string.start_state_deactive));
+								m_tvStatus.setTextColor(getResources().getColor(R.color.connectivity_off));
+								((TextView) m_viewContent.findViewById(R.id.anon_tv_tip)).setText("");
 								((ProgressBar) m_viewContent.findViewById(R.id.anon_iv_statusbar)).setProgress(0);
-							}
+								m_tvLocation.setText(getContext().getString(R.string.start_loc_unknown));
+								break;
 
+						}
 					}
-				else
-					{
-						Log.e("ANONFragment", "VPN is not running!");
-						sw.setChecked(false);
-
-						m_TrafficStatisticsHandler.removeCallbacks(m_TrafficStatisticsTask);
-						m_TrafficStatisticsTask.isScheduled = false;
-						updateTrafficStatistics(IVPNInterface.RxTx.ALL_ZERO);
-
-						m_tvStatus.setText(getContext().getString(R.string.start_state_deactive));
-						m_tvStatus.setTextColor(getResources().getColor(R.color.connectivity_off));
-						((TextView) m_viewContent.findViewById(R.id.anon_tv_tip)).setText("");
-						((ProgressBar) m_viewContent.findViewById(R.id.anon_iv_statusbar)).setProgress(0);
-						m_tvLocation.setText(getContext().getString(R.string.start_loc_unknown));
-					}
+				}
 			}
 	}
diff --git a/app/src/main/java/anonvpn/anon_next/android/ui/main/MainActivity.java b/app/src/main/java/anonvpn/anon_next/android/ui/main/MainActivity.java
index 1015ade..d904ae0 100644
--- a/app/src/main/java/anonvpn/anon_next/android/ui/main/MainActivity.java
+++ b/app/src/main/java/anonvpn/anon_next/android/ui/main/MainActivity.java
@@ -31,6 +31,8 @@ import anonvpn.anon_next.android.ui.SettingsActivity;
 import anonvpn.anon_next.android.ui.VPNConnectedActivity;
 import anonvpn.anon_next.android.ui.tutorial.TutorialActivity;
 import anonvpn.anon_next.core.CascadeConnectionManager;
+import anonvpn.anon_next.core.gui.VPNState;
+import anonvpn.anon_next.core.notification.Event;
 
 //Main Activity of ANONmobile
 public class MainActivity extends VPNConnectedActivity implements NavigationView.OnNavigationItemSelectedListener
@@ -41,10 +43,15 @@ public class MainActivity extends VPNConnectedActivity implements NavigationView
 		public static final int FRAGMENTID_CONNECTION = 1;
 		public static final int FRAGMENTID_APPS = 2;
 		public static final int FRAGMENTID_NETWORKS = 3;
-		private int mActiveFragment = -1;
+		private int mActiveFragment = FRAGMENTID_ANONYMITY;
 		private final int ALLOW_VPN_REQUEST = 0;
 		private final int CHOOSE_CONNECTION_REQUEST = 1;
 
+		private final AnonFragment mAnonFragment = new AnonFragment();
+		private final ConnectFragment mConnectFragment = new ConnectFragment();
+		private final NetFragment mNetFragment = new NetFragment();
+		private final AppFragment mAppFragment = new AppFragment();
+
 		private FragmentManager mFragmentManager = null;
 		private SharedPreferences mSharedPreferences = null;
 
@@ -98,6 +105,8 @@ public class MainActivity extends VPNConnectedActivity implements NavigationView
 
 				mSharedPreferences = getSharedPreferences(this.getString(R.string.sp_global), Context.MODE_PRIVATE);
 
+				launchMainView();
+
 				if (mSharedPreferences.getBoolean("TutorialPassed", false) == false)
 					{
 						Intent intent = new Intent(this, TutorialActivity.class);
@@ -110,29 +119,12 @@ public class MainActivity extends VPNConnectedActivity implements NavigationView
 			{
 				String LOGTAG = "MainActivity";
 				Log.i(LOGTAG, "Received new intent");
-				int target_fragment = intent.getIntExtra("FragmentID", -1);
-				if (target_fragment != -1)
-					{
-						// On redirect from connection overview to anon fragment also check WAITING_FOR_CASCADE_CONNECTED
-						// TODO: Else display an error message after a timeout
-						if (mActiveFragment == FRAGMENTID_CONNECTION && target_fragment == FRAGMENTID_ANONYMITY)
-							{
-								ConnectFragment current_fragment = (ConnectFragment) mFragmentManager.findFragmentById(R.id.fl_fragmentcontainer);
-								if (current_fragment != null && current_fragment.WAITING_FOR_CASCADE_CONNECTED)
-									{
-										current_fragment.WAITING_FOR_CASCADE_CONNECTED = false;
-										setFragment(target_fragment);
-									}
-							}
-						else
-							{
-								setFragment(target_fragment);
-							}
-					}
-				else
-					{
-//					launchMainView();
-					}
+				System.out.println("Got Notification");
+				if (intent.hasExtra("type") && intent.getStringExtra("type").equals("notification")) {
+					System.out.println("Updating anon fragment!");
+					mAnonFragment.updateStatus();
+
+				}
 			}
 
 
@@ -163,24 +155,7 @@ public class MainActivity extends VPNConnectedActivity implements NavigationView
 				NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
 				navigationView.setNavigationItemSelectedListener(this);
 
-				setFragment(FRAGMENTID_ANONYMITY);
-
-				if (mSharedPreferences.getBoolean("VPNStarted", false) && !getServiceInterface().tunnelingEnabled())
-					{
-						enableVPNTunneling();
-					}
-				else
-					{
-						Fragment fragment = mFragmentManager.findFragmentById(R.id.fl_fragmentcontainer);
-						if (fragment != null)
-							{
-
-								if (fragment instanceof AnonFragment)
-									{
-										((AnonFragment) fragment).updateStatus();
-									}
-							}
-					}
+				setFragment(mActiveFragment);
 			}
 
 		public void enableVPNTunneling()
@@ -210,12 +185,6 @@ public class MainActivity extends VPNConnectedActivity implements NavigationView
 			{
 				Log.e("AndroidVPNMainActivity", "Enable tunneling device!");
 				getServiceInterface().enableTunneling();
-
-				Fragment fragment = mFragmentManager.findFragmentById(R.id.fl_fragmentcontainer);
-				if (fragment instanceof AnonFragment && fragment != null)
-					{
-						((AnonFragment) fragment).updateStatus();
-					}
 			}
 
 		public void disableVPNTunneling()
@@ -244,8 +213,10 @@ public class MainActivity extends VPNConnectedActivity implements NavigationView
 		protected void onVPNServiceConnected()
 			{
 
-				launchMainView();
-
+				if (mSharedPreferences.getBoolean("VPNStarted", false) && getServiceInterface().getServiceState() != VPNState.DISABLED)
+				{
+					enableVPNTunneling();
+				}
 			}
 
 		protected void onVPNServiceDisconnected()
@@ -393,22 +364,26 @@ public class MainActivity extends VPNConnectedActivity implements NavigationView
 								switch (id)
 									{
 										case FRAGMENTID_ANONYMITY:
-											mFragmentManager.beginTransaction().replace(R.id.fl_fragmentcontainer, new AnonFragment()).commit();
+											//mAnonFragment = new AnonFragment();
+											mFragmentManager.beginTransaction().replace(R.id.fl_fragmentcontainer, mAnonFragment).commit();
 											setTheme(R.style.AppTheme_SwitchBig);
 											setTitle(R.string.start_title);
 											break;
 										case FRAGMENTID_CONNECTION:
-											mFragmentManager.beginTransaction().replace(R.id.fl_fragmentcontainer, new ConnectFragment()).commit();
+											//mConnectFragment = new ConnectFragment();
+											mFragmentManager.beginTransaction().replace(R.id.fl_fragmentcontainer, mConnectFragment).commit();
 											setTheme(R.style.AppTheme);
 											setTitle(R.string.connect_title);
 											break;
 										case FRAGMENTID_APPS:
-											mFragmentManager.beginTransaction().replace(R.id.fl_fragmentcontainer, new AppFragment()).commit();
+											//mAppFragment = new AppFragment();
+											mFragmentManager.beginTransaction().replace(R.id.fl_fragmentcontainer, mAppFragment).commit();
 											setTheme(R.style.AppTheme);
 											setTitle(R.string.app_title);
 											break;
 										case FRAGMENTID_NETWORKS:
-											mFragmentManager.beginTransaction().replace(R.id.fl_fragmentcontainer, new NetFragment()).commit();
+											//mNetFragment = new NetFragment();
+											mFragmentManager.beginTransaction().replace(R.id.fl_fragmentcontainer, mNetFragment).commit();
 											setTheme(R.style.AppTheme);
 											setTitle(R.string.net_title);
 											break;
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 0d61f54..ddbb0af 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -10,7 +10,8 @@
 
     <!-- Connectivity status -->
     <color name="connectivity_off">#E53935</color>
-    <color name="connectivity_problem">#FFDD00</color>
+    <color name="connectivity_fatal">#ff0d00</color>
+    <color name="connectivity_problem">#ff8400</color>
     <color name="connectivity_ok">#43A047</color>
 
     <!-- Buttons -->
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5b5e726..b0319e5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -64,14 +64,14 @@
     <string name="start_label_loc">Deutschland</string>
     <string name="start_label_observer">(für Beobachter)</string>
     <string name="start_label_unit"> kB/s</string>
-    <string name="start_state_nocon">Es besteht keine Verbindung zu einem Netz</string>
+    <string name="start_state_nocon">Es besteht keine Verbindung zu einem Netz.</string>
     <string name="start_loc_unknown">Unbekannt</string>
     <string name="start_tip_choosenet">Wähle dich in ein Netz ein, um die Anonymisierung zu beginnen.</string>
     <string name="start_state_nonet">"Das aktuelle Netz ist nicht anonym!"</string>
     <string name="start_state_active">Sie sind anonym!</string>
     <string name="start_state_deactive">Sie sind nicht anonym!</string>
     <string name="start_label_noconnect">Verbindungsproblem!</string>
-    <string name="start_tip_nocon">Der Anonymisierungsdienst scheint nicht erreichbar zu sein. Wählen Sie bitte einen anderen Anonymisierungsdienst und überprüfen Sie ihre Internetverbindung.</string>
+    <string name="start_state_noservice">Es konnte keine Verbindung zum Anonymisierungsdienst aufgebaut werden.</string>
     <string name="start_tip_net">Sie müssen mit einem Netz verbunden sein, um den Dienst zu aktivieren.</string>
     <string name="start_state_establish">Verbindung wird aufgebaut</string>
     <string name="start_meter_mixamount">Tipp: Wähle eine Verbindung mit mehr Verbindungspunkten, um deine Anonymität zu verstärken</string>
@@ -322,6 +322,8 @@ Deshalb sollten vor allem Webanwendungen die JavaScript, Java oder Flash verwend
 
 
     <string name="vpn_tunneling_shutdown_progress_notification">Beende Anonymisierung...</string>
+    <string name="foregroundservice_desc_connecting">Verbinde zum Anonymisierungsdienst...</string>
+    <string name="foregroundservice_desc_network">Warte auf Verbindung zum Internet</string>
 
 
 </resources>
-- 
GitLab