diff --git a/app/build.gradle b/app/build.gradle
index cdeccb6c836d6370967f69c87e199ce34989188b..718e91331b25686985b8edf2b400fe0a55fdffa2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -75,8 +75,9 @@ dependencies {
   compile 'org.thoughtcrime.ssl.pinning:AndroidPinning:1.0.0'
   compile 'com.squareup.okhttp3:okhttp:3.9.0'
   compile 'mbanje.kurt:fabbutton:1.1.4'
-  compile 'com.android.support:support-annotations:25.3.1'
-  compile 'com.android.support:support-v4:26.0.0-alpha1'
+  compile "com.android.support:support-core-utils:26.1.0"
+  compile 'com.android.support:support-annotations:26.1.0'
+  compile 'com.android.support:support-v4:26.1.0'
 }
 
 def processFileInplace(file, Closure processText) {
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
index 86e1bb02b0cbac9f217aa0f7b80b431478dd339b..f52c30d9efe9b96bf8a336a03a68e4ab292aa0da 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
@@ -243,8 +243,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
             //noinspection NewApi
             nbuilder.setChannelId(channel);
             if (mProfile != null)
-             //noinspection NewApi
-            nbuilder.setShortcutId(mProfile.getUUIDString());
+                //noinspection NewApi
+                nbuilder.setShortcutId(mProfile.getUUIDString());
 
         }
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/BitmaskApp.java b/app/src/main/java/se/leap/bitmaskclient/BitmaskApp.java
index 953a559d780de217062a58949059b8a12f02d12c..d7f574b23915a3bdb973111c58b2d9bc978a0097 100644
--- a/app/src/main/java/se/leap/bitmaskclient/BitmaskApp.java
+++ b/app/src/main/java/se/leap/bitmaskclient/BitmaskApp.java
@@ -1,6 +1,16 @@
 package se.leap.bitmaskclient;
 
+import android.annotation.TargetApi;
 import android.app.Application;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+
+import de.blinkt.openvpn.core.OpenVPNService;
+
+import static android.os.Build.VERSION_CODES.O;
 
 /**
  * Created by cyberta on 24.10.17.
@@ -13,5 +23,42 @@ public class BitmaskApp extends Application {
         super.onCreate();
         PRNGFixes.apply();
         //TODO: add LeakCanary!
+        if (Build.VERSION.SDK_INT >= O)
+            createNotificationChannelsForOpenvpn();
     }
+
+
+    @TargetApi(O)
+    private void createNotificationChannelsForOpenvpn() {
+        NotificationManager mNotificationManager =
+                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+
+        // Background message
+        CharSequence name = getString(R.string.channel_name_background);
+        NotificationChannel mChannel = new NotificationChannel(OpenVPNService.NOTIFICATION_CHANNEL_BG_ID,
+                name, NotificationManager.IMPORTANCE_MIN);
+
+        mChannel.setDescription(getString(R.string.channel_description_background));
+        mChannel.enableLights(false);
+
+        mChannel.setLightColor(Color.DKGRAY);
+        mNotificationManager.createNotificationChannel(mChannel);
+
+        // Connection status change messages
+
+        name = getString(R.string.channel_name_status);
+        mChannel = new NotificationChannel(OpenVPNService.NOTIFICATION_CHANNEL_NEWSTATUS_ID,
+                name, NotificationManager.IMPORTANCE_DEFAULT);
+
+
+        mChannel.setDescription(getString(R.string.channel_description_status));
+        mChannel.enableLights(true);
+
+        mChannel.setLightColor(Color.BLUE);
+        mNotificationManager.createNotificationChannel(mChannel);
+
+    }
+
+
+
 }
diff --git a/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java b/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java
index 57c066aa367c96238539f890be2da9c3d9ce620d..77aa17c15366822ce27ee5d684e17ee6cd39a6c3 100644
--- a/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java
@@ -35,15 +35,12 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
 
-import org.jetbrains.annotations.NotNull;
-
 import java.util.Observable;
 import java.util.Observer;
 
 import butterknife.ButterKnife;
 import butterknife.InjectView;
 import butterknife.OnClick;
-import de.blinkt.openvpn.core.ConnectionStatus;
 import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
 import de.blinkt.openvpn.core.OpenVPNService;
 import de.blinkt.openvpn.core.ProfileManager;
@@ -55,11 +52,7 @@ import se.leap.bitmaskclient.eip.EipStatus;
 import se.leap.bitmaskclient.eip.VoidVpnService;
 
 import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK;
-import static se.leap.bitmaskclient.eip.EipStatus.EipLevel.BLOCKING;
-import static se.leap.bitmaskclient.eip.EipStatus.EipLevel.CONNECTED;
-import static se.leap.bitmaskclient.eip.EipStatus.EipLevel.CONNECTING;
-import static se.leap.bitmaskclient.eip.EipStatus.EipLevel.DISCONNECTED;
-import static se.leap.bitmaskclient.eip.EipStatus.EipLevel.DISCONNECTING;
+import static se.leap.bitmaskclient.eip.Constants.ACTION_STOP_BLOCKING_VPN;
 
 public class VpnFragment extends Fragment implements Observer {
 
@@ -160,7 +153,7 @@ public class VpnFragment extends Fragment implements Observer {
             handleSwitchOff();
         else
             handleSwitchOn();
-
+        //FIXME ONBOOT IS BROKEN!
         saveStatus(eip_status.isConnected() || eip_status.isConnecting());
     }
 
@@ -197,6 +190,7 @@ public class VpnFragment extends Fragment implements Observer {
         } else if (eip_status.isConnected()) {
             askToStopEIP();
         } else if (eip_status.isBlocking()) {
+            //FIXME DEAD CODE
             stop();
         } else {
             updateIcon();
@@ -230,14 +224,19 @@ public class VpnFragment extends Fragment implements Observer {
     }
 
     private void stop() {
-
         if (eip_status.isBlockingVpnEstablished()) {
-            Log.d(TAG, "stop VoidVpn!");
-            VoidVpnService.stop();
+            stopBlockingVpn();
         }
         disconnect();
     }
 
+    private void stopBlockingVpn() {
+        Log.d(TAG, "stop VoidVpn!");
+        Intent stopVoidVpnIntent = new Intent(dashboard, VoidVpnService.class);
+        stopVoidVpnIntent.setAction(ACTION_STOP_BLOCKING_VPN);
+        dashboard.startService(stopVoidVpnIntent);
+    }
+
     private void disconnect() {
         ProfileManager.setConntectedVpnProfileDisconnected(dashboard);
         if (mService != null) {
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Constants.java b/app/src/main/java/se/leap/bitmaskclient/eip/Constants.java
index ed4ebcbcdc4271e6678b647387cb559acab0279d..449c111d06632a5ddf1e60c70c1480f9a22a876e 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/Constants.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/Constants.java
@@ -31,6 +31,8 @@ public interface Constants {
     public final static String ACTION_STOP_EIP = TAG + ".STOP_EIP";
     public final static String ACTION_UPDATE_EIP_SERVICE = TAG + ".UPDATE_EIP_SERVICE";
     public final static String ACTION_IS_EIP_RUNNING = TAG + ".IS_RUNNING";
+    public final static String ACTION_START_BLOCKING_VPN = TAG + ".ACTION_START_BLOCKING_VPN";
+    public final static String ACTION_STOP_BLOCKING_VPN = TAG + ".ACTION_STOP_BLOCKING_VPN";
     public final static String EIP_NOTIFICATION = TAG + ".EIP_NOTIFICATION";
     public final static String ALLOWED_ANON = "allow_anonymous";
     public final static String ALLOWED_REGISTERED = "allow_registration";
@@ -39,7 +41,6 @@ public interface Constants {
     public final static String KEY = TAG + ".KEY";
     public final static String RECEIVER_TAG = TAG + ".RECEIVER_TAG";
     public final static String REQUEST_TAG = TAG + ".REQUEST_TAG";
-    public final static String START_BLOCKING_VPN_PROFILE = TAG + ".START_BLOCKING_VPN_PROFILE";
     public final static String PROVIDER_CONFIGURED = TAG + ".PROVIDER_CONFIGURED";
     public final static String IS_ALWAYS_ON = TAG + ".IS_ALWAYS_ON";
     public final static String RESTART_ON_BOOT = TAG + ".RESTART_ON_BOOT";
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java
index dc2e81f5c8a1439ab6bd41b3ddd3208579fc1faa..b1d7c994791c076d3dbee1faf9a9692598eef7d9 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java
@@ -66,12 +66,17 @@ public class EipStatus extends Observable implements VpnStatus.StateListener {
 
     @Override
     public void updateState(final String state, final String logmessage, final int localizedResId, final ConnectionStatus level) {
+        ConnectionStatus tmp = current_status.getLevel();
         current_status = getInstance();
         current_status.setState(state);
         current_status.setLogMessage(logmessage);
         current_status.setLocalizedResId(localizedResId);
         current_status.setLevel(level);
         current_status.setEipLevel(level);
+        if (tmp != current_status.getLevel()) {
+            current_status.setChanged();
+            current_status.notifyObservers();
+        }
     }
 
     @Override
@@ -80,7 +85,6 @@ public class EipStatus extends Observable implements VpnStatus.StateListener {
 
 
     private void setEipLevel(ConnectionStatus level) {
-        EipLevel tmp = current_eip_level;
         switch (level) {
             case LEVEL_CONNECTED:
                 current_eip_level = EipLevel.CONNECTED;
@@ -105,10 +109,6 @@ public class EipStatus extends Observable implements VpnStatus.StateListener {
                 current_eip_level = EipLevel.UNKNOWN; //??
                 break;
         }
-        if (tmp != current_eip_level) {
-            current_status.setChanged();
-            current_status.notifyObservers();
-        }
     }
 
     @VisibleForTesting
@@ -117,8 +117,8 @@ public class EipStatus extends Observable implements VpnStatus.StateListener {
     }
 
     /**
-     * This method intends to ignore states that are valid for less than a second.
-     * This way flickering UI changes can be avoided
+     * This is a debouncing method ignoring states that are valid for less than a second.
+     * This way flickering UI changes can be avoided.
      *
      * @param futureLevel
      */
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java
index 5c9263b3d7d739fd7926b23e12892616885e0427..27e2d95e5305c4a3e73a48256ad71b5135c27060 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java
@@ -28,8 +28,12 @@ public class VoidVpnLauncher extends Activity {
         if (requestCode == VPN_USER_PERMISSION) {
             if (resultCode == RESULT_OK) {
                 Intent void_vpn_service = new Intent(getApplicationContext(), VoidVpnService.class);
-                void_vpn_service.setAction(Constants.START_BLOCKING_VPN_PROFILE);
-                startService(void_vpn_service);
+                void_vpn_service.setAction(Constants.ACTION_START_BLOCKING_VPN);
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                    startForegroundService(void_vpn_service);
+                } else {
+                    startService(void_vpn_service);
+                }
             }
         }
         finish();
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java
index 46c010ca2f4c772a0b2cacc6d82ab5ed94d414db..e5e50f6ec6dc5651ee88511abda3d1dd974600e0 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java
@@ -1,35 +1,61 @@
 package se.leap.bitmaskclient.eip;
 
+import android.annotation.TargetApi;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.graphics.Color;
 import android.net.VpnService;
 import android.os.Build;
 import android.os.ParcelFileDescriptor;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationManagerCompat;
 import android.util.Log;
 
 import java.io.IOException;
+import java.util.Observable;
+import java.util.Observer;
 
 import de.blinkt.openvpn.core.ConnectionStatus;
 import de.blinkt.openvpn.core.VpnStatus;
+import se.leap.bitmaskclient.Dashboard;
 import se.leap.bitmaskclient.R;
 
+import static android.os.Build.VERSION_CODES.O;
 import static se.leap.bitmaskclient.Dashboard.SHARED_PREFERENCES;
 import static se.leap.bitmaskclient.eip.Constants.ACTION_START_ALWAYS_ON_EIP;
+import static se.leap.bitmaskclient.eip.Constants.ACTION_STOP_BLOCKING_VPN;
 
 
-public class VoidVpnService extends VpnService {
+public class VoidVpnService extends VpnService implements Observer {
 
     static final String TAG = VoidVpnService.class.getSimpleName();
     static ParcelFileDescriptor fd;
     static Thread thread;
     private final int ALWAYS_ON_MIN_API_LEVEL = Build.VERSION_CODES.N;
     private static final String STATE_ESTABLISH = "ESTABLISHVOIDVPN";
-    private static final String STATE_STOP = "STOPVOIDVPN";
+    public static final String NOTIFICATION_CHANNEL_NEWSTATUS_ID = "bitmask_void_vpn_news";
+    private EipStatus eipStatus;
+    NotificationManager notificationManager;
+    NotificationManagerCompat compatNotificationManager;
 
     @Override
-    public int onStartCommand(final Intent intent, int flags, int startId) {
+    public void onCreate() {
+        super.onCreate();
+        notificationManager =  (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+        compatNotificationManager = NotificationManagerCompat.from(this);
+        eipStatus = EipStatus.getInstance();
+        eipStatus.addObserver(this);
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
         String action = intent != null ? intent.getAction() : "";
-        if (action.equals(Constants.START_BLOCKING_VPN_PROFILE)) {
+        if (action.equals(Constants.ACTION_START_BLOCKING_VPN)) {
             thread = new Thread(new Runnable() {
                 public void run() {
                     establishBlockingVpn();
@@ -51,6 +77,8 @@ public class VoidVpnService extends VpnService {
                 }
             });
             thread.run();
+        } else if (action.equals(ACTION_STOP_BLOCKING_VPN)) {
+            stop();
         }
         return START_STICKY;
     }
@@ -61,12 +89,28 @@ public class VoidVpnService extends VpnService {
         closeFd();
     }
 
-    public static void stop() {
-        if (thread != null)
+    @TargetApi(O)
+    private void createNotificationChannel() {
+
+        // Connection status change messages
+        CharSequence name = getString(R.string.channel_name_status);
+        NotificationChannel mChannel = new NotificationChannel(VoidVpnService.NOTIFICATION_CHANNEL_NEWSTATUS_ID,
+                name, NotificationManagerCompat.IMPORTANCE_DEFAULT);
+
+        mChannel.setDescription(getString(R.string.channel_description_status));
+        mChannel.enableLights(true);
+
+        mChannel.setLightColor(Color.BLUE);
+        notificationManager.createNotificationChannel(mChannel);
+    }
+
+
+    private void stop() {
+        stopNotifications();
+        if (thread != null) {
             thread.interrupt();
+        }
         closeFd();
-        VpnStatus.updateStateString(STATE_STOP, "",
-                R.string.void_vpn_stopped, ConnectionStatus.LEVEL_NOTCONNECTED);
     }
 
     public static boolean isRunning() throws NullPointerException {
@@ -114,12 +158,101 @@ public class VoidVpnService extends VpnService {
     private void requestVpnWithLastSelectedProfile() {
         Intent startEIP = new Intent(getApplicationContext(), EIP.class);
         startEIP.setAction(ACTION_START_ALWAYS_ON_EIP);
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            //noinspection NewApi
-            getApplicationContext().startForegroundService(startEIP);
+        getApplicationContext().startService(startEIP);
+    }
+
+    @Override
+    public void update(Observable observable, Object arg) {
+        if (observable instanceof EipStatus) {
+            eipStatus = (EipStatus) observable;
+        }
+
+        if (thread == null) {
+            return;
+        }
+
+        if (eipStatus.isBlockingVpnEstablished()) {
+            showNotification(getString(eipStatus.getLocalizedResId()),
+                    getString(eipStatus.getLocalizedResId()), eipStatus.getLevel());
         } else {
-            getApplicationContext().startService(startEIP);
+            stopNotifications();
         }
     }
 
+    private void stopNotifications() {
+        stopForeground(true);
+        compatNotificationManager.cancel(NOTIFICATION_CHANNEL_NEWSTATUS_ID.hashCode());
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
+                notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_NEWSTATUS_ID) != null) {
+            notificationManager.deleteNotificationChannel(NOTIFICATION_CHANNEL_NEWSTATUS_ID);
+        }
+    }
+
+    /**
+     * @param msg
+     * @param tickerText
+     * @param status
+     */
+    private void showNotification(final String msg, String tickerText, ConnectionStatus status) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            createNotificationChannel();
+        }
+
+        int icon = getIconByConnectionStatus(status);
+        NotificationCompat.Builder nCompatBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_NEWSTATUS_ID);
+
+        nCompatBuilder.setContentTitle(getString(R.string.notifcation_title_bitmask, getString(R.string.void_vpn_title)));
+        nCompatBuilder.setCategory(NotificationCompat.CATEGORY_SERVICE);
+        nCompatBuilder.setLocalOnly(true);
+        nCompatBuilder.setContentText(msg);
+        nCompatBuilder.setOnlyAlertOnce(true);
+        nCompatBuilder.setSmallIcon(icon);
+        if (tickerText != null && !tickerText.equals("")) {
+            nCompatBuilder.setTicker(tickerText);
+        }
+
+        nCompatBuilder.setContentIntent(getDashboardIntent());
+        //TODO: implement extra Dashboard.ACTION_ASK_TO_CANCEL_BLOCKING_VPN
+        NotificationCompat.Action.Builder builder = new NotificationCompat.Action.Builder(R.drawable.ic_menu_close_clear_cancel, getString(R.string.vpn_button_turn_off_blocking), getStopVoidVpnIntent());
+        nCompatBuilder.addAction(builder.build());
+
+        Notification notification = nCompatBuilder.build();
+        int notificationId = NOTIFICATION_CHANNEL_NEWSTATUS_ID.hashCode();
+        compatNotificationManager.notify(notificationId, notification);
+        startForeground(notificationId, notification);
+    }
+
+    private PendingIntent getDashboardIntent() {
+        Intent startDashboard = new Intent(this, Dashboard.class);
+        startDashboard.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+                Intent.FLAG_ACTIVITY_SINGLE_TOP);
+        return PendingIntent.getActivity(this, 0, startDashboard, PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+
+    private PendingIntent getStopVoidVpnIntent() {
+        Intent stopVoidVpnIntent = new Intent (this, VoidVpnService.class);
+        stopVoidVpnIntent.setAction(Constants.ACTION_STOP_BLOCKING_VPN);
+        return PendingIntent.getService(this, 0, stopVoidVpnIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+
+    //TODO: replace with getIconByEipLevel(EipLevel level)
+    private int getIconByConnectionStatus(ConnectionStatus level) {
+        switch (level) {
+            case LEVEL_CONNECTED:
+                return R.drawable.ic_stat_vpn;
+            case LEVEL_AUTH_FAILED:
+            case LEVEL_NONETWORK:
+            case LEVEL_NOTCONNECTED:
+                return R.drawable.ic_stat_vpn_offline;
+            case LEVEL_CONNECTING_NO_SERVER_REPLY_YET:
+            case LEVEL_WAITING_FOR_USER_INPUT:
+            case LEVEL_CONNECTING_SERVER_REPLIED:
+                return R.drawable.ic_stat_vpn_outline;
+            case LEVEL_BLOCKING:
+                return R.drawable.ic_stat_vpn_blocking;
+            case UNKNOWN_LEVEL:
+            default:
+                return R.drawable.ic_stat_vpn_offline;
+        }
+    }
 }
diff --git a/build.gradle b/build.gradle
index dc2396d7f7492f052fbc78639f43ebd21422de23..7917b9d67903deba56442d3beeafbf61178c4436 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,5 +16,8 @@ allprojects {
   repositories {
     mavenCentral()
     jcenter()
+    maven {
+      url "https://maven.google.com"
+    }
   }
 }