diff --git a/app/build.gradle b/app/build.gradle
index c4286d29084fe001787089608c88f09356b63090..1d94258403795ea0720f66a4a947d248261f6b9f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,7 +3,7 @@ apply plugin: 'android'
 
 android {
   compileSdkVersion 21
-  buildToolsVersion "21.1.2"
+  buildToolsVersion "22.0.1"
 
   signingConfigs {
     release {
@@ -39,13 +39,14 @@ android {
 }
 
 dependencies {
-  androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.3.1'
-  compile 'com.jakewharton:butterknife:6.0.0+'
-  provided 'com.squareup.dagger:dagger-compiler:1.2.2+'
-  compile 'com.github.pedrovgs:renderers:1.3+'
+  androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.4.1'
+  compile 'com.jakewharton:butterknife:6.1.0'
+  provided 'com.squareup.dagger:dagger-compiler:1.2.2'
+  compile 'com.github.pedrovgs:renderers:1.5'
   compile 'com.intellij:annotations:12.0'
-  compile 'com.google.code.gson:gson:2+'
+  compile 'com.google.code.gson:gson:2.3.1'
   compile 'org.thoughtcrime.ssl.pinning:AndroidPinning:1.0.0'
+  compile 'mbanje.kurt:fabbutton:1.1.1'
 }
 
 def processFileInplace(file, Closure processText) {
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/BaseTestDashboard.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/BaseTestDashboard.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a9131fdafbb5d2185f16a165bc7223bb31a2e0e
--- /dev/null
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/BaseTestDashboard.java
@@ -0,0 +1,61 @@
+package se.leap.bitmaskclient.test;
+
+import android.content.*;
+import android.graphics.*;
+import android.test.*;
+import android.view.*;
+
+import com.robotium.solo.*;
+
+import se.leap.bitmaskclient.*;
+
+public abstract class BaseTestDashboard extends ActivityInstrumentationTestCase2<Dashboard> {
+
+    Solo solo;
+    Context context;
+    UserStatusTestController user_status_controller;
+    VpnTestController vpn_controller;
+
+    public BaseTestDashboard() { super(Dashboard.class); }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        context = getInstrumentation().getContext();
+        solo = new Solo(getInstrumentation(), getActivity());
+        user_status_controller = new UserStatusTestController(solo);
+        vpn_controller = new VpnTestController(solo);
+        ConnectionManager.setMobileDataEnabled(true, context);
+        solo.unlockScreen();
+        if (solo.searchText(solo.getString(R.string.configuration_wizard_title)))
+            new testConfigurationWizard(solo).toDashboardAnonymously("demo.bitmask.net");
+    }
+
+    void changeProviderAndLogIn(String provider) {
+        tapSwitchProvider();
+        solo.clickOnText(provider);
+        useRegistered();
+    }
+
+    void tapSwitchProvider() {
+        solo.clickOnMenuItem(solo.getString(R.string.switch_provider_menu_option));
+        solo.waitForActivity(ConfigurationWizard.class);
+    }
+
+    private void useRegistered() {
+        String text = solo.getString(R.string.signup_or_login_button);
+        clickAndWaitForDashboard(text);
+        user_status_controller.logIn("parmegvtest10", "holahola2");
+    }
+
+    private void clickAndWaitForDashboard(String click_text) {
+        solo.clickOnText(click_text);
+        assertTrue(solo.waitForActivity(Dashboard.class, 80 * 1000));
+    }
+
+    static boolean isShownWithinConfinesOfVisibleScreen(View view) {
+        Rect scrollBounds = new Rect();
+        view.getHitRect(scrollBounds);
+        return view.getLocalVisibleRect(scrollBounds);
+    }
+}
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/Screenshot.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/Screenshot.java
new file mode 100644
index 0000000000000000000000000000000000000000..91d51402493445edfb58956fa332ceeafac0ffff
--- /dev/null
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/Screenshot.java
@@ -0,0 +1,55 @@
+package se.leap.bitmaskclient.test;
+
+import com.robotium.solo.*;
+
+import java.text.*;
+import java.util.*;
+
+public class Screenshot {
+    private static String default_name = Screenshot.class.getPackage().getName();
+    private static DateFormat date_format = DateFormat.getDateTimeInstance();
+    private static int DEFAULT_MILLISECONDS_TO_SLEEP = 500;
+    private static int milliseconds_to_sleep = 0;
+    private static Solo solo;
+
+    public static void initialize(Solo solo) {
+        Screenshot.solo = solo;
+    }
+
+    public static void take(String name) {
+        solo.takeScreenshot(name.replace(" ", "_") + " " + getTimeStamp());
+    }
+
+    public static void takeWithSleep(String name) {
+        sleepBefore();
+        take(name);
+    }
+
+    public static void take() {
+        sleepBefore();
+        solo.takeScreenshot(default_name + "_" + getTimeStamp());
+    }
+
+    public static void takeWithSleep() {
+        sleepBefore();
+        take();
+    }
+
+    private static String getTimeStamp() {
+        return date_format.format(Calendar.getInstance().getTime()).replace(" ", "_").replace("/", "_").replace(":", "_");
+    }
+
+    public static void setTimeToSleep(double seconds) {
+        long milliseconds_to_sleep = Math.round(seconds * 1000);
+        Screenshot.milliseconds_to_sleep = Math.round(milliseconds_to_sleep);
+    }
+
+    private static void sleepBefore() {
+        if(milliseconds_to_sleep == 0)
+            solo.sleep(DEFAULT_MILLISECONDS_TO_SLEEP);
+        else
+            solo.sleep(milliseconds_to_sleep);
+        milliseconds_to_sleep = 0;
+    }
+}
+
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/UserStatusTestController.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/UserStatusTestController.java
new file mode 100644
index 0000000000000000000000000000000000000000..138dfa71268c3232cedc73f5422e8f2c2ce2fcdc
--- /dev/null
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/UserStatusTestController.java
@@ -0,0 +1,70 @@
+package se.leap.bitmaskclient.test;
+
+import android.view.*;
+
+import com.robotium.solo.*;
+
+import se.leap.bitmaskclient.*;
+
+public class UserStatusTestController {
+    private final Solo solo;
+
+    public UserStatusTestController(Solo solo) {
+        this.solo = solo;
+    }
+
+    void clickUserSessionButton() {
+        solo.clickOnView(getUserSessionButton());
+    }
+
+    View getUserSessionButton() throws IllegalStateException {
+        View view = solo.getView(R.id.user_status_button);
+        if(view == null)
+            throw new IllegalStateException();
+
+        return view;
+    }
+
+    void logIn(String username, String password) {
+        solo.enterText(0, username);
+        solo.enterText(1, password);
+        solo.clickOnText(solo.getString(R.string.login_button));
+        solo.waitForDialogToClose();
+        assertLoggedIn();
+    }
+
+    private void assertLoggedIn() {
+        String log_out = solo.getString(R.string.logout_button);
+        solo.waitForText(log_out);
+    }
+
+    void assertLoggedOut() {
+        String log_in = solo.getString(R.string.login_button);
+        solo.waitForText(log_in);
+    }
+
+    void logOut() {
+        assertLoggedIn();
+        clickUserSessionButton();
+
+        solo.clickOnActionBarItem(R.string.logout_button);
+        solo.waitForDialogToClose();
+        assertLoggedOut();
+    }
+
+    boolean assertErrorLogInDialogAppears() {
+        solo.waitForDialogToOpen();
+
+        String username_hint = solo.getEditText(0).getHint().toString();
+        String correct_username_hint = solo.getString(R.string.username_hint);
+        String password_hint = solo.getEditText(1).getHint().toString();
+        String correct_password_hint = solo.getString(R.string.password_hint);
+        String user_message = solo.getText(0).toString();
+        String riseup_user_message = solo.getString(R.string.login_riseup_warning);
+
+        return username_hint.equalsIgnoreCase(correct_username_hint)
+                && password_hint.equalsIgnoreCase(correct_password_hint)
+                && !user_message.equalsIgnoreCase(riseup_user_message)
+                && !user_message.isEmpty();
+    }
+}
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java
new file mode 100644
index 0000000000000000000000000000000000000000..25d81da10080b8c075f986efe2b531749334b533
--- /dev/null
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java
@@ -0,0 +1,161 @@
+package se.leap.bitmaskclient.test;
+
+import android.graphics.*;
+import android.graphics.drawable.*;
+import android.view.*;
+import android.widget.*;
+
+import com.robotium.solo.*;
+
+import junit.framework.AssertionFailedError;
+
+import de.blinkt.openvpn.activities.*;
+import mbanje.kurt.fabbutton.*;
+import se.leap.bitmaskclient.R;
+
+public class VpnTestController {
+
+    private final Solo solo;
+
+    public VpnTestController(Solo solo) {
+        this.solo = solo;
+    }
+
+    protected void turnVpnOndAndOff(String provider) {
+        clickVpnButton();
+        turningEipOn();
+        clickVpnButton();
+        turningEipOff();
+    }
+
+    protected void clickVpnButton() throws IllegalStateException {
+        Button button = getVpnButton();
+        if(!isVpnButton(button))
+            throw new IllegalStateException();
+        solo.clickOnView(button);
+    }
+
+    protected Button getVpnButton() {
+        try {
+            View button_view = solo.getView(R.id.vpn_main_button);
+            if (button_view != null)
+                return (Button) button_view;
+            else
+                return new Button(solo.getCurrentActivity());
+        } catch (AssertionFailedError e) {
+            return new Button(solo.getCurrentActivity());
+        }
+    }
+
+    private boolean isVpnButton(Button button) {
+        return !button.getText().toString().isEmpty();
+    }
+
+    protected FabButton getVpnWholeIcon() {
+        View view = solo.getView(R.id.vpn_Status_Image);
+        if (view != null)
+            return (FabButton) view;
+        else
+            return null;
+    }
+
+    protected void turningEipOn() {
+        assertInProgress();
+        int max_seconds_until_connected = 120;
+
+        Condition condition = new Condition() {
+            @Override
+            public boolean isSatisfied() {
+                return iconShowsConnected();
+            }
+        };
+        solo.waitForCondition(condition, max_seconds_until_connected * 1000);
+        sleepSeconds(2);
+    }
+
+    private void assertInProgress() {
+        FabButton whole_icon = getVpnWholeIcon();
+        ProgressRingView a;
+        a = whole_icon != null ?
+                (ProgressRingView) getVpnWholeIcon().findViewById(R.id.fabbutton_ring) :
+                new ProgressRingView(solo.getCurrentActivity());
+        BaseTestDashboard.isShownWithinConfinesOfVisibleScreen(a);
+    }
+
+    private boolean iconShowsConnected() {
+        return iconEquals(iconConnectedDrawable());
+    }
+
+    protected boolean iconShowsDisconnected() {
+        return iconEquals(iconDisconnectedDrawable());
+    }
+
+    private boolean iconEquals(Drawable drawable) {
+        Bitmap inside_icon = getVpnInsideIcon();
+        if(inside_icon != null)
+            return inside_icon.equals(drawable);
+        else
+            return false;
+
+    }
+
+    private Drawable iconConnectedDrawable() {
+        return getDrawable(R.drawable.ic_stat_vpn);
+    }
+
+    private Drawable iconDisconnectedDrawable() {
+        return getDrawable(R.drawable.ic_stat_vpn_offline);
+    }
+
+    private Drawable getDrawable(int resId) {
+        return solo.getCurrentActivity().getResources().getDrawable(resId);
+    }
+
+    private Bitmap getVpnInsideIcon() {
+        FabButton whole_icon = getVpnWholeIcon();
+
+        CircleImageView a;
+        a = whole_icon != null ?
+                (CircleImageView) getVpnWholeIcon().findViewById(R.id.fabbutton_circle)
+                : new CircleImageView(solo.getCurrentActivity());
+        a.setDrawingCacheEnabled(true);
+        return a.getDrawingCache();
+    }
+
+    protected void turningEipOff() {
+        okToBrowserWarning();
+        sayOkToDisconnect();
+
+        int max_seconds_until_connected = 1;
+
+        Condition condition = new Condition() {
+            @Override
+            public boolean isSatisfied() {
+                return iconShowsDisconnected();
+            }
+        };
+        solo.waitForCondition(condition, max_seconds_until_connected * 1000);
+        sleepSeconds(2);
+    }
+
+    private void okToBrowserWarning() {
+        solo.waitForDialogToOpen();
+        clickYes();
+    }
+
+    private void clickYes() {
+        String yes = solo.getString(android.R.string.yes);
+        solo.clickOnText(yes);
+    }
+
+    private void sayOkToDisconnect() throws IllegalStateException {
+        boolean disconnect_vpn_appeared = solo.waitForActivity(DisconnectVPN.class);
+        if(disconnect_vpn_appeared)
+            clickYes();
+        else throw new IllegalStateException();
+    }
+
+    void sleepSeconds(int seconds) {
+        solo.sleep(seconds * 1000);
+    }
+}
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/testConfigurationWizard.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/testConfigurationWizard.java
index 1fa4cf2fa7224b4af339d9c9f742c31b313c8a03..931457eed0f7cda6e552804cdab23558c19bb909 100644
--- a/app/src/androidTest/java/se/leap/bitmaskclient/test/testConfigurationWizard.java
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/testConfigurationWizard.java
@@ -13,6 +13,7 @@ public class testConfigurationWizard extends ActivityInstrumentationTestCase2<Co
 
     private Solo solo;
     private static int added_providers;
+    private boolean executing_from_dashboard = false;
 
     public testConfigurationWizard() {
         super(ConfigurationWizard.class);
@@ -21,18 +22,21 @@ public class testConfigurationWizard extends ActivityInstrumentationTestCase2<Co
     public testConfigurationWizard(Solo solo) {
         super(ConfigurationWizard.class);
         this.solo = solo;
+        executing_from_dashboard = true;
     }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         solo = new Solo(getInstrumentation(), getActivity());
-        ConnectionManager.setMobileDataEnabled(true, solo.getCurrentActivity().getApplicationContext());
+        //ConnectionManager.setMobileDataEnabled(true, solo.getCurrentActivity().getApplicationContext());
     }
 
     @Override
     protected void tearDown() throws Exception {
-
+        if(!executing_from_dashboard)
+            solo.finishOpenedActivities();
+        super.tearDown();
     }
 
     public void testListProviders() {
@@ -68,7 +72,7 @@ public class testConfigurationWizard extends ActivityInstrumentationTestCase2<Co
 
     private void waitForProviderDetails() {
         String text = solo.getString(R.string.provider_details_fragment_title);
-        assertTrue("Provider details dialog did not appear", solo.waitForText(text));
+        assertTrue("Provider details dialog did not appear", solo.waitForText(text, 1, 60*1000));
     }
 
     public void testAddNewProvider() {
@@ -77,6 +81,7 @@ public class testConfigurationWizard extends ActivityInstrumentationTestCase2<Co
 
     private void addProvider(String url) {
         boolean is_new_provider = !solo.searchText(url);
+
         if (is_new_provider)
             added_providers = added_providers + 1;
         solo.clickOnActionBarItem(R.id.new_provider);
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/testDashboardIntegration.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/testDashboardIntegration.java
index d2fb9901beccbc95c4c86e764233578bad05b05f..fea6bf77ae2711682cebee3615bd6ac56399f59b 100644
--- a/app/src/androidTest/java/se/leap/bitmaskclient/test/testDashboardIntegration.java
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/testDashboardIntegration.java
@@ -1,136 +1,29 @@
 package se.leap.bitmaskclient.test;
 
-import android.content.*;
-import android.test.*;
-import android.widget.*;
+import android.graphics.*;
+import android.graphics.drawable.Drawable;
+import android.widget.Button;
 
 import com.robotium.solo.*;
 
 import java.io.*;
 
 import de.blinkt.openvpn.activities.*;
+import mbanje.kurt.fabbutton.CircleImageView;
+import mbanje.kurt.fabbutton.FabButton;
+import mbanje.kurt.fabbutton.ProgressRingView;
 import se.leap.bitmaskclient.*;
 
-public class testDashboardIntegration extends ActivityInstrumentationTestCase2<Dashboard> {
-
-    private Solo solo;
-    private Context context;
-
-    public testDashboardIntegration() {
-        super(Dashboard.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        context = getInstrumentation().getContext();
-        solo = new Solo(getInstrumentation(), getActivity());
-        ConnectionManager.setMobileDataEnabled(true, context);
-        solo.unlockScreen();
-        if (solo.searchText(solo.getString(R.string.configuration_wizard_title)))
-            new testConfigurationWizard(solo).toDashboardAnonymously("demo.bitmask.net");
-    }
+public class testDashboardIntegration extends BaseTestDashboard {
 
     @Override
     protected void tearDown() throws Exception {
         solo.finishOpenedActivities();
     }
 
-    /**
-     * This test will fail if Android does not trust VPN connection.
-     * I cannot automate that dialog.
-     */
-    public void testOnOffOpenVpn() {
-        solo.clickOnView(solo.getView(R.id.eipSwitch));
-        turningEipOn();
-
-        solo.clickOnView(solo.getView(R.id.eipSwitch));
-        turningEipOff();
-
-        solo.clickOnView(solo.getView(R.id.eipSwitch));
-        turningEipOn();
-
-        solo.clickOnView(solo.getView(R.id.eipSwitch));
-        turningEipOff();
-
-        /*solo.clickOnView(solo.getView(R.id.eipSwitch));
-        turningEipOn();
-	    
-	    turnNetworkOff();
-        restartAdbServer(); // This doesn't work
-        */
-
-    }
-
-    private void turningEipOn() {
-        assertAuthenticating();
-        int max_seconds_until_connected = 30;
-        assertConnected(max_seconds_until_connected);
-        solo.sleep(2 * 1000);
-    }
-
-    private void assertAuthenticating() {
-        String message = solo.getString(R.string.state_auth);
-        assertTrue(solo.waitForText(message));
-    }
-
-    private void assertConnected(int max_seconds_until_connected) {
-        String message = solo.getString(R.string.eip_state_connected);
-        assertTrue(solo.waitForText(message, 1, max_seconds_until_connected * 1000));
-    }
-
-    private void turningEipOff() {
-        sayOkToDisconnect();
-        assertDisconnected();
-        solo.sleep(2 * 1000);
-    }
-
-    private void sayOkToDisconnect() {
-        assertTrue(solo.waitForActivity(DisconnectVPN.class));
-        String yes = solo.getString(android.R.string.yes);
-        solo.clickOnText(yes);
-    }
-
-    private void assertDisconnected() {
-        String message = solo.getString(R.string.eip_state_not_connected);
-        assertTrue(solo.waitForText(message));
-    }
-
-    private void turnNetworkOff() {
-        ConnectionManager.setMobileDataEnabled(false, context);
-        if (!solo.waitForText(getActivity().getString(R.string.eip_state_not_connected), 1, 15 * 1000))
-            fail();
-    }
-
-    private void restartAdbServer() {
-        runAdbCommand("kill-server");
-        runAdbCommand("start-server");
-    }
-
-    public void testLogInAndOut() {
-        long milliseconds_to_log_in = 40 * 1000;
-        solo.clickOnActionBarItem(R.id.login_button);
-        logIn("parmegvtest1", " S_Zw3'-");
-        solo.waitForDialogToClose(milliseconds_to_log_in);
-        assertSuccessfulLogin();
-
-        logOut();
-    }
-
-    private void logIn(String username, String password) {
-        solo.enterText(0, username);
-        solo.enterText(1, password);
-        solo.clickOnText("Log In");
-        solo.waitForDialogToClose();
-    }
-
-    private void assertSuccessfulLogin() {
-        assertTrue(solo.waitForText("is logged in"));
-    }
-
-    private void logOut() {
-        solo.clickOnActionBarItem(R.string.logout_button);
-        assertTrue(solo.waitForDialogToClose());
+    public void testSwitchProvider() {
+        tapSwitchProvider();
+        solo.goBack();
     }
 
     public void testShowAbout() {
@@ -141,79 +34,25 @@ public class testDashboardIntegration extends ActivityInstrumentationTestCase2<D
     }
 
     private void showAbout() {
-        String menu_item = solo.getString(R.string.about);
-        solo.clickOnMenuItem(menu_item);
-
+        clickAbout();
         String text_unique_to_about = solo.getString(R.string.repository_url_text);
         solo.waitForText(text_unique_to_about);
     }
 
-    public void testSwitchProvider() {
-	tapSwitchProvider();
-        solo.goBack();
-    }
-
-    private void tapSwitchProvider() {
-        solo.clickOnMenuItem(solo.getString(R.string.switch_provider_menu_option));
-        solo.waitForActivity(ConfigurationWizard.class);
-    }
-
-    public void testEveryProvider() {
-	changeProvider("demo.bitmask.net");
-	connectVpn();
-	disconnectVpn();
-	
-	changeProvider("riseup.net");
-	connectVpn();
-	disconnectVpn();
-
-	changeProvider("calyx.net");
-	connectVpn();
-	disconnectVpn();
-    }
-
-    private void changeProvider(String provider) {
-	tapSwitchProvider();
-        solo.clickOnText(provider);
-	useRegistered();
-	solo.waitForText("Downloading VPN certificate");
-	assertDisconnected();
-    }
-
-    private void connectVpn() {
-	Switch vpn_switch = (Switch)solo.getView(R.id.eipSwitch);
-	assertFalse(vpn_switch.isChecked());
-
-	solo.clickOnView(vpn_switch);
-        turningEipOn();
-    }
-
-    private void disconnectVpn() {
-	Switch vpn_switch = (Switch)solo.getView(R.id.eipSwitch);
-	assertTrue(vpn_switch.isChecked());
-
-	solo.clickOnView(vpn_switch);
-	solo.clickOnText("Yes");
-        turningEipOff();
-	
-    }
-
-    private void useRegistered() {
-        String text = solo.getString(R.string.signup_or_login_button);
-        clickAndWaitForDashboard(text);
-        login();
+    private void clickAbout() {
+        String menu_item = solo.getString(R.string.about);
+        solo.clickOnMenuItem(menu_item);
     }
 
-    private void clickAndWaitForDashboard(String click_text) {
-        solo.clickOnText(click_text);
-        assertTrue(solo.waitForActivity(Dashboard.class, 5000));
+    private void turnNetworkOff() {
+        ConnectionManager.setMobileDataEnabled(false, context);
+        if (!solo.waitForText(getActivity().getString(R.string.eip_state_not_connected), 1, 15 * 1000))
+            fail();
     }
 
-    private void login() {
-        long milliseconds_to_log_in = 40 * 1000;
-        logIn("parmegvtest10", "holahola2");
-        solo.waitForDialogToClose(milliseconds_to_log_in);
-        assertSuccessfulLogin();
+    private void restartAdbServer() {
+        runAdbCommand("kill-server");
+        runAdbCommand("start-server");
     }
     
     /*public void testReboot() {
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/testUserStatusFragment.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/testUserStatusFragment.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e791d16d7430478b5d6925adea2c05f7f8252c6
--- /dev/null
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/testUserStatusFragment.java
@@ -0,0 +1,31 @@
+package se.leap.bitmaskclient.test;
+
+public class testUserStatusFragment extends BaseTestDashboard {
+
+    public final String TAG = testUserStatusFragment.class.getName();
+
+    private final String provider = "demo.bitmask.net";
+    private final String test_username = "parmegvtest1";
+    private final String test_password = " S_Zw3'-";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        changeProviderAndLogIn(provider);
+        user_status_controller.clickUserSessionButton();
+        user_status_controller.assertLoggedOut();
+    }
+
+    public void testLogInAndOut() {
+        user_status_controller.clickUserSessionButton();
+        user_status_controller.logIn(test_username, test_password);
+        user_status_controller.logOut();
+    }
+
+    public void testFailedLogIn() {
+        user_status_controller.clickUserSessionButton();
+        user_status_controller.logIn(test_username, TAG);
+        if(!user_status_controller.assertErrorLogInDialogAppears())
+            throw new IllegalStateException();
+    }
+}
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/testVpnFragment.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/testVpnFragment.java
new file mode 100644
index 0000000000000000000000000000000000000000..106d5cf23e1ac195c16d6204e611ba6a2d788756
--- /dev/null
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/testVpnFragment.java
@@ -0,0 +1,72 @@
+package se.leap.bitmaskclient.test;
+
+public class testVpnFragment extends BaseTestDashboard {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        Screenshot.initialize(solo);
+    }
+
+    /**
+     * This test will fail if Android does not trust VPN connection.
+     * I cannot automate that dialog.
+     */
+    public void testOnOffOpenVpn() {
+        Screenshot.take("Initial UI");
+        vpn_controller.clickVpnButton();
+        Screenshot.setTimeToSleep(5);
+        Screenshot.takeWithSleep("Turning VPN on");
+        vpn_controller.turningEipOn();
+        Screenshot.setTimeToSleep(0.5);
+        Screenshot.takeWithSleep("VPN turned on");
+
+        vpn_controller.clickVpnButton();
+        vpn_controller.turningEipOff();
+        Screenshot.take("VPN turned off");
+
+        vpn_controller.clickVpnButton();
+        vpn_controller.turningEipOn();
+
+        vpn_controller.clickVpnButton();
+        vpn_controller.turningEipOff();
+
+        /*clickVpnButton();;
+        turningEipOn();
+
+	    turnNetworkOff();
+        restartAdbServer(); // This doesn't work
+        */
+
+    }
+
+    /**
+     * Run only if the trust this app dialog has not been checked.
+     * You must pay attention to the screen, because you need to cancel de dialog twice (block vpn and normal vpn)
+     */
+    public void testOnFailed() {
+        /* TODO Do not rely on the Android's vpn trust dialog
+        vpn_controller.clickVpnButton();
+        assertTrue("Have you checked the trust vpn dialog?", solo.waitForActivity(LogWindow.class));
+        solo.goBack();
+        assertTrue(vpn_controller.iconShowsDisconnected());
+        */
+    }
+
+    public void testVpnEveryProvider() {
+        String[] providers = {"demo.bitmask.net", "riseup.net", "calyx.net"};
+        for(String provider : providers) {
+            changeProviderAndLogIn(provider);
+            vpn_controller.sleepSeconds(1);
+            vpn_controller.turnVpnOndAndOff(provider);
+            vpn_controller.sleepSeconds(1);
+        }
+    }
+
+    public void testVpnIconIsDisplayed() {
+        assertTrue(isShownWithinConfinesOfVisibleScreen(vpn_controller.getVpnWholeIcon()));
+    }
+    public void testVpnButtonIsDisplayed() {
+        assertTrue(isShownWithinConfinesOfVisibleScreen(vpn_controller.getVpnButton()));
+    }
+}
diff --git a/app/src/debug/java/se/leap/bitmaskclient/ConfigurationWizard.java b/app/src/debug/java/se/leap/bitmaskclient/ConfigurationWizard.java
index aac53a078dcab746dc361c6eab3ef3464700fa10..2505d37b544f078e6e0ad79def64df76fcac5d02 100644
--- a/app/src/debug/java/se/leap/bitmaskclient/ConfigurationWizard.java
+++ b/app/src/debug/java/se/leap/bitmaskclient/ConfigurationWizard.java
@@ -40,6 +40,7 @@ import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver;
 import se.leap.bitmaskclient.ProviderDetailFragment.ProviderDetailFragmentInterface;
 import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
 import se.leap.bitmaskclient.eip.*;
+import se.leap.bitmaskclient.userstatus.SessionDialog;
 
 /**
  * Activity that builds and shows the list of known available providers.
@@ -97,8 +98,7 @@ public class ConfigurationWizard extends Activity
             outState.putInt(PROGRESSBAR_NUMBER, mProgressBar.getProgress());
         if (progressbar_description != null)
             outState.putString(PROGRESSBAR_TEXT, progressbar_description.getText().toString());
-        if (selected_provider != null)
-            outState.putParcelable(Provider.KEY, selected_provider);
+        outState.putParcelable(Provider.KEY, selected_provider);
         super.onSaveInstanceState(outState);
     }
 
@@ -125,8 +125,7 @@ public class ConfigurationWizard extends Activity
         progress = savedInstanceState.getInt(PROGRESSBAR_NUMBER, -1);
 
         if (fragment_manager.findFragmentByTag(ProviderDetailFragment.TAG) == null && setting_up_provider) {
-            if (selected_provider != null)
-                onItemSelectedUi();
+            onItemSelectedUi();
             if (progress > 0)
                 mProgressBar.setProgress(progress);
         }
@@ -166,8 +165,7 @@ public class ConfigurationWizard extends Activity
     }
 
     private void setUpProviderAPIResultReceiver() {
-        providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler());
-        providerAPI_result_receiver.setReceiver(this);
+        providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler(), this);
         providerAPI_broadcast_receiver_update = new ProviderAPIBroadcastReceiver_Update();
 
         IntentFilter update_intent_filter = new IntentFilter(ProviderAPI.UPDATE_PROGRESSBAR);
@@ -196,8 +194,6 @@ public class ConfigurationWizard extends Activity
                 mProgressBar.incrementProgressBy(1);
                 hideProgressBar();
 
-                setResult(RESULT_OK);
-
                 showProviderDetails();
             }
         } else if (resultCode == ProviderAPI.PROVIDER_NOK) {
@@ -205,8 +201,6 @@ public class ConfigurationWizard extends Activity
             preferences.edit().remove(Provider.KEY).apply();
             setting_up_provider = false;
 
-            setResult(RESULT_CANCELED, mConfigState);
-
             String reason_to_fail = resultData.getString(ProviderAPI.ERRORS);
             showDownloadFailedDialog(reason_to_fail);
         } else if (resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) {
@@ -214,13 +208,10 @@ public class ConfigurationWizard extends Activity
             hideProgressBar();
 
             showProviderDetails();
-
-            setResult(RESULT_OK);
         } else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) {
             hideProgressBar();
             cancelSettingUpProvider();
             Toast.makeText(getApplicationContext(), R.string.provider_problem, Toast.LENGTH_LONG).show();
-            setResult(RESULT_CANCELED, mConfigState);
         } else if (resultCode == AboutActivity.VIEWED) {
             // Do nothing, right now
             // I need this for CW to wait for the About activity to end before going back to Dashboard.
@@ -393,7 +384,7 @@ public class ConfigurationWizard extends Activity
     public void setUpProvider(boolean danger_on) {
         Intent provider_API_command = new Intent(this, ProviderAPI.class);
         Bundle parameters = new Bundle();
-        parameters.putString(Provider.MAIN_URL, selected_provider.mainUrl().toString());
+        parameters.putString(Provider.MAIN_URL, selected_provider.mainUrl().getUrl().toString());
         parameters.putBoolean(ProviderItem.DANGER_ON, danger_on);
         parameters.putString(Provider.CA_CERT_FINGERPRINT, selected_provider.certificatePin());
 
diff --git a/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java
index 6c57fca21fe23f4f1adb2b2406c75adb8b105c5b..2d7e13fedc49b75195ee67d448085be026fcff1f 100644
--- a/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java
+++ b/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java
@@ -38,6 +38,9 @@ import javax.net.ssl.*;
 
 import se.leap.bitmaskclient.ProviderListContent.*;
 import se.leap.bitmaskclient.eip.*;
+import se.leap.bitmaskclient.userstatus.SessionDialog;
+import se.leap.bitmaskclient.userstatus.User;
+import se.leap.bitmaskclient.userstatus.UserStatus;
 
 /**
  * Implements HTTP api methods used to manage communications with the provider server.
@@ -145,7 +148,7 @@ public class ProviderAPI extends IntentService {
                 receiver.send(PROVIDER_NOK, result);
             }
         } else if (action.equalsIgnoreCase(SIGN_UP)) {
-            UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.SIGNING_UP, resources);
+            UserStatus.updateStatus(UserStatus.SessionStatus.SIGNING_UP, resources);
             Bundle result = tryToRegister(parameters);
             if (result.getBoolean(RESULT_KEY)) {
                 receiver.send(SUCCESSFUL_SIGNUP, result);
@@ -153,23 +156,24 @@ public class ProviderAPI extends IntentService {
                 receiver.send(FAILED_SIGNUP, result);
             }
         } else if (action.equalsIgnoreCase(LOG_IN)) {
-            UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGING_IN, resources);
+            UserStatus.updateStatus(UserStatus.SessionStatus.LOGGING_IN, resources);
             Bundle result = tryToAuthenticate(parameters);
             if (result.getBoolean(RESULT_KEY)) {
                 receiver.send(SUCCESSFUL_LOGIN, result);
-                UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGED_IN, resources);
+                UserStatus.updateStatus(UserStatus.SessionStatus.LOGGED_IN, resources);
             } else {
                 receiver.send(FAILED_LOGIN, result);
-                UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.NOT_LOGGED_IN, resources);
+                UserStatus.updateStatus(UserStatus.SessionStatus.NOT_LOGGED_IN, resources);
             }
         } else if (action.equalsIgnoreCase(LOG_OUT)) {
-            UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGING_OUT, resources);
+            UserStatus.updateStatus(UserStatus.SessionStatus.LOGGING_OUT, resources);
             if (logOut()) {
                 receiver.send(SUCCESSFUL_LOGOUT, Bundle.EMPTY);
-                UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGED_OUT, resources);
+                android.util.Log.d(TAG, "Logged out, notifying user status");
+                UserStatus.updateStatus(UserStatus.SessionStatus.LOGGED_OUT, resources);
             } else {
                 receiver.send(LOGOUT_FAILED, Bundle.EMPTY);
-                UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.DIDNT_LOG_OUT, resources);
+                UserStatus.updateStatus(UserStatus.SessionStatus.DIDNT_LOG_OUT, resources);
             }
         } else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) {
             if (updateVpnCertificate()) {
@@ -695,7 +699,7 @@ public class ProviderAPI extends IntentService {
         String[] pins = new String[] {ca_cert_fingerprint};
         try {
             URL url = new URL(url_string);
-            HttpsURLConnection connection = PinningHelper.getPinnedHttpsURLConnection(Dashboard.getContext(), pins, url);
+            HttpsURLConnection connection = PinningHelper.getPinnedHttpsURLConnection(getApplicationContext(), pins, url);
             connection.setConnectTimeout(seconds_of_timeout * 1000);
             if (!LeapSRPSession.getToken().isEmpty())
                 connection.addRequestProperty(LeapSRPSession.AUTHORIZATION_HEADER, "Token token = " + LeapSRPSession.getToken());
diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
index 4207872d08acd9b531030682d2618b629dd6c93a..bdc36e8934df6123c4b22177b98f9db1245dd8d3 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
@@ -29,11 +29,10 @@ import org.jetbrains.annotations.*;
 import org.json.*;
 
 import java.net.*;
-import java.util.*;
 
 import butterknife.*;
-import de.blinkt.openvpn.activities.*;
 import se.leap.bitmaskclient.eip.*;
+import se.leap.bitmaskclient.userstatus.*;
 
 /**
  * The main user facing Activity of Bitmask Android, consisting of status, controls,
@@ -42,7 +41,7 @@ import se.leap.bitmaskclient.eip.*;
  * @author Sean Leonard <meanderingcode@aetherislands.net>
  * @author parmegv
  */
-public class Dashboard extends Activity implements SessionDialog.SessionDialogInterface, ProviderAPIResultReceiver.Receiver, Observer {
+public class Dashboard extends Activity implements ProviderAPIResultReceiver.Receiver {
 
     protected static final int CONFIGURE_LEAP = 0;
     protected static final int SWITCH_PROVIDER = 1;
@@ -62,14 +61,10 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
 
     @InjectView(R.id.providerName)
     TextView provider_name;
-    @InjectView(R.id.user_session_status)
-    TextView user_session_status_text_view;
-    @InjectView(R.id.user_session_status_progress)
-    ProgressBar user_session_status_progress_bar;
-
-    EipFragment eip_fragment;
-    private Provider provider;
-    private UserSessionStatus user_session_status;
+
+    VpnFragment eip_fragment;
+    UserStatusFragment user_status_fragment;
+    private static Provider provider = new Provider();
     public ProviderAPIResultReceiver providerAPI_result_receiver;
     private boolean switching_provider;
 
@@ -78,22 +73,23 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
         super.onCreate(savedInstanceState);
 
         app = this;
-        user_session_status = UserSessionStatus.getInstance(getResources());
-        user_session_status.addObserver(this);
 
         PRNGFixes.apply();
 
         preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
         fragment_manager = new FragmentManagerEnhanced(getFragmentManager());
         handleVersion();
-        User.init();
+        User.init(getString(R.string.default_username));
+
+        ProviderAPICommand.initialize(this);
+        providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler(), this);
 
         restoreProvider(savedInstanceState);
-        if (provider == null || provider.getName().isEmpty())
+        if (!provider.isConfigured())
             startActivityForResult(new Intent(this, ConfigurationWizard.class), CONFIGURE_LEAP);
         else {
             buildDashboard(getIntent().getBooleanExtra(ON_BOOT, false));
-            restoreSessionStatus(savedInstanceState);
+            user_status_fragment.restoreSessionStatus(savedInstanceState);
         }
     }
 
@@ -102,32 +98,20 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
             if (savedInstanceState.containsKey(Provider.KEY))
                 provider = savedInstanceState.getParcelable(Provider.KEY);
         }
-        if (provider == null && preferences.getBoolean(Constants.PROVIDER_CONFIGURED, false))
+        if (!provider.isConfigured() && preferences.getBoolean(Constants.PROVIDER_CONFIGURED, false))
             provider = getSavedProviderFromSharedPreferences();
     }
 
-    private void restoreSessionStatus(Bundle savedInstanceState) {
-        if (savedInstanceState != null)
-            if (savedInstanceState.containsKey(UserSessionStatus.TAG)) {
-                UserSessionStatus.SessionStatus status = (UserSessionStatus.SessionStatus) savedInstanceState.getSerializable(UserSessionStatus.TAG);
-                user_session_status.updateStatus(status, getResources());
-            }
-    }
-
     @Override
     protected void onSaveInstanceState(@NotNull Bundle outState) {
-        if (provider != null)
-            outState.putParcelable(Provider.KEY, provider);
-        if (user_session_status_text_view != null && user_session_status_text_view.getVisibility() == TextView.VISIBLE)
-            outState.putSerializable(UserSessionStatus.TAG, user_session_status.sessionStatus());
-
+        outState.putParcelable(Provider.KEY, provider);
         super.onSaveInstanceState(outState);
     }
 
     private Provider getSavedProviderFromSharedPreferences() {
-        Provider provider = null;
+        Provider provider = new Provider();
         try {
-            provider = new Provider(new URL(preferences.getString(Provider.MAIN_URL, "")));
+            provider.setUrl(new URL(preferences.getString(Provider.MAIN_URL, "")));
             provider.define(new JSONObject(preferences.getString(Provider.KEY, "")));
         } catch (MalformedURLException | JSONException e) {
             e.printStackTrace();
@@ -162,12 +146,12 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
                 providerToPreferences(provider);
 
                 buildDashboard(false);
-                invalidateOptionsMenu();
+                invalidateOptionsMenuOnUiThread();
                 if (data.hasExtra(SessionDialog.TAG)) {
                     sessionDialog(Bundle.EMPTY);
                 }
 
-            } else if (resultCode == RESULT_CANCELED && data.hasExtra(ACTION_QUIT)) {
+            } else if (resultCode == RESULT_CANCELED && data != null && data.hasExtra(ACTION_QUIT)) {
                 finish();
             } else
                 configErrorDialog();
@@ -214,33 +198,35 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
         ButterKnife.inject(this);
 
         provider_name.setText(provider.getDomain());
+
+        user_status_fragment = new UserStatusFragment();
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(Provider.ALLOW_REGISTRATION, provider.allowsRegistration());
+        user_status_fragment.setArguments(bundle);
+        fragment_manager.replace(R.id.user_status_fragment, user_status_fragment, UserStatusFragment.TAG);
+
         if (provider.hasEIP()) {
-            fragment_manager.removePreviousFragment(EipFragment.TAG);
-            eip_fragment = new EipFragment();
+            fragment_manager.removePreviousFragment(VpnFragment.TAG);
+            eip_fragment = new VpnFragment();
 
             if (hide_and_turn_on_eip) {
                 preferences.edit().remove(Dashboard.START_ON_BOOT).apply();
                 Bundle arguments = new Bundle();
-                arguments.putBoolean(EipFragment.START_ON_BOOT, true);
+                arguments.putBoolean(VpnFragment.START_ON_BOOT, true);
                 if (eip_fragment != null) eip_fragment.setArguments(arguments);
             }
 
-            fragment_manager.replace(R.id.servicesCollection, eip_fragment, EipFragment.TAG);
+            fragment_manager.replace(R.id.servicesCollection, eip_fragment, VpnFragment.TAG);
             if (hide_and_turn_on_eip) {
                 onBackPressed();
             }
         }
-        handleNewUserSessionStatus(user_session_status);
     }
 
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
         if (provider.allowsRegistration()) {
             menu.findItem(R.id.signup_button).setVisible(true);
-
-            boolean logged_in = User.loggedIn();
-            menu.findItem(R.id.login_button).setVisible(!logged_in);
-            menu.findItem(R.id.logout_button).setVisible(logged_in);
         }
         return true;
     }
@@ -262,15 +248,9 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
                 return true;
             case R.id.switch_provider:
                 switching_provider = true;
-                if (LeapSRPSession.loggedIn()) logOut();
+                if (User.loggedIn()) user_status_fragment.logOut();
                 else switchProvider();
                 return true;
-            case R.id.login_button:
-                sessionDialog(Bundle.EMPTY);
-                return true;
-            case R.id.logout_button:
-                logOut();
-                return true;
             case R.id.signup_button:
                 sessionDialog(Bundle.EMPTY);
                 return true;
@@ -285,131 +265,22 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
     }
 
     public void showLog() {
-        Intent startLW = new Intent(getContext(), LogWindow.class);
-        startActivity(startLW);
-    }
-
-    @Override
-    public void signUp(String username, String password) {
-        User.setUserName(username);
-        Bundle parameters = bundlePassword(password);
-        providerApiCommand(parameters, 0, ProviderAPI.SIGN_UP);
-    }
-
-    @Override
-    public void logIn(String username, String password) {
-        User.setUserName(username);
-        Bundle parameters = bundlePassword(password);
-        providerApiCommand(parameters, 0, ProviderAPI.LOG_IN);
-    }
-
-    public void logOut() {
-        providerApiCommand(Bundle.EMPTY, 0, ProviderAPI.LOG_OUT);
-    }
-
-    @Override
-    public void update(Observable observable, Object data) {
-        if (observable instanceof UserSessionStatus) {
-            UserSessionStatus status = (UserSessionStatus) observable;
-            handleNewUserSessionStatus(status);
-        }
-    }
-
-    private void handleNewUserSessionStatus(UserSessionStatus status) {
-        user_session_status = status;
-        if (provider.allowsRegistration()) {
-            if (user_session_status.inProgress())
-                showUserSessionProgressBar();
-            else
-                hideUserSessionProgressBar();
-            changeSessionStatusMessage(user_session_status.toString());
-            invalidateOptionsMenu();
-        }
-    }
-
-    private void changeSessionStatusMessage(final String message) {
-        runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                user_session_status_text_view.setText(message);
-            }
-        });
-    }
-
-    private void showUserSessionProgressBar() {
-        runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                user_session_status_progress_bar.setVisibility(ProgressBar.VISIBLE);
-            }
-        });
-    }
-
-    private void hideUserSessionProgressBar() {
-        runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                user_session_status_progress_bar.setVisibility(ProgressBar.GONE);
-            }
-        });
+        LogWindowWrapper log_window_wrapper = LogWindowWrapper.getInstance(getContext());
+        log_window_wrapper.showLog();
     }
 
-    protected void downloadVpnCertificate() {
-        boolean is_authenticated = LeapSRPSession.loggedIn();
+    public void downloadVpnCertificate() {
+        boolean is_authenticated = User.loggedIn();
         boolean allowed_anon = preferences.getBoolean(Constants.ALLOWED_ANON, false);
         if (allowed_anon || is_authenticated)
-            providerApiCommand(Bundle.EMPTY, R.string.downloading_certificate_message, ProviderAPI.DOWNLOAD_CERTIFICATE);
+            ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.DOWNLOAD_CERTIFICATE, providerAPI_result_receiver);
         else
             sessionDialog(Bundle.EMPTY);
-
-    }
-
-    private Bundle bundlePassword(String password) {
-        Bundle parameters = new Bundle();
-        if (!password.isEmpty())
-            parameters.putString(SessionDialog.PASSWORD, password);
-        return parameters;
-    }
-
-    protected void providerApiCommand(Bundle parameters, int progressbar_message_resId, String providerApi_action) {
-        if (eip_fragment != null && progressbar_message_resId != 0) {
-            eip_fragment.progress_bar.setVisibility(ProgressBar.VISIBLE);
-            setStatusMessage(progressbar_message_resId);
-        }
-
-        Intent command = prepareProviderAPICommand(parameters, providerApi_action);
-        startService(command);
-    }
-
-    private Intent prepareProviderAPICommand(Bundle parameters, String action) {
-        providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler());
-        providerAPI_result_receiver.setReceiver(this);
-
-        Intent command = new Intent(this, ProviderAPI.class);
-
-        command.putExtra(ProviderAPI.PARAMETERS, parameters);
-        command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver);
-        command.setAction(action);
-        return command;
-    }
-
-    public void cancelLoginOrSignup() {
-        EipStatus.getInstance().setConnectedOrDisconnected();
     }
 
     public void sessionDialog(Bundle resultData) {
-
         FragmentTransaction transaction = fragment_manager.removePreviousFragment(SessionDialog.TAG);
-
-        DialogFragment newFragment = new SessionDialog();
-        if (provider.getName().equalsIgnoreCase("riseup")) {
-            resultData = resultData == Bundle.EMPTY ? new Bundle() : resultData;
-            resultData.putBoolean(SessionDialog.ERRORS.RISEUP_WARNING.toString(), true);
-        }
-        if (resultData != null && !resultData.isEmpty()) {
-            newFragment.setArguments(resultData);
-        }
-        newFragment.show(transaction, SessionDialog.TAG);
+        SessionDialog.getInstance(provider, resultData).show(transaction, SessionDialog.TAG);
     }
 
     private void switchProvider() {
@@ -425,7 +296,7 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
         if (resultCode == ProviderAPI.SUCCESSFUL_SIGNUP) {
             String username = resultData.getString(SessionDialog.USERNAME);
             String password = resultData.getString(SessionDialog.PASSWORD);
-            logIn(username, password);
+            user_status_fragment.logIn(username, password);
         } else if (resultCode == ProviderAPI.FAILED_SIGNUP) {
             sessionDialog(resultData);
         } else if (resultCode == ProviderAPI.SUCCESSFUL_LOGIN) {
@@ -438,7 +309,6 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
             setResult(RESULT_CANCELED);
         } else if (resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) {
             eip_fragment.updateEipService();
-            eip_fragment.handleNewVpnCertificate();
             setResult(RESULT_OK);
         } else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) {
             setResult(RESULT_CANCELED);
@@ -450,18 +320,24 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
         }
     }
 
-    private void setStatusMessage(int string_resId) {
-        if (eip_fragment != null && eip_fragment.status_message != null)
-            eip_fragment.status_message.setText(string_resId);
-    }
-
     public static Context getContext() {
         return app;
     }
 
+    public static Provider getProvider() { return provider; }
+
     @Override
     public void startActivityForResult(Intent intent, int requestCode) {
         intent.putExtra(Dashboard.REQUEST_CODE, requestCode);
         super.startActivityForResult(intent, requestCode);
     }
+
+    public void invalidateOptionsMenuOnUiThread() {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                invalidateOptionsMenu();
+            }
+        });
+    }
 }
diff --git a/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java b/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java
new file mode 100644
index 0000000000000000000000000000000000000000..8daa7d8c27081bc7871225b7f01758ffcd2e8882
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java
@@ -0,0 +1,37 @@
+package se.leap.bitmaskclient;
+
+import java.net.*;
+
+public class DefaultedURL {
+    private URL DEFAULT_URL;
+    private String default_url = "https://example.net";
+
+    private URL url;
+
+    public DefaultedURL() {
+        try {
+            DEFAULT_URL = new URL(default_url);
+            url = DEFAULT_URL;
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public boolean isDefault() { return url.equals(DEFAULT_URL); }
+
+    public void setUrl(URL url) {
+        this.url = url;
+    }
+
+    public String getDomain() {
+        return url.getHost();
+    }
+
+    public URL getUrl() {
+        return url;
+    }
+
+    public String toString() {
+        return url.toString();
+    }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java
index 1ced6d60a0ed3a43ce54b2382df62b7e14218f2e..49cf37744daeec19502ae48fe7dfd9d33ab5229f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java
+++ b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java
@@ -337,7 +337,7 @@ public class LeapSRPSession {
         return token;
     }
 
-    protected static boolean loggedIn() {
+    public static boolean loggedIn() {
         return !token.isEmpty();
     }
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/LogWindowWrapper.java b/app/src/main/java/se/leap/bitmaskclient/LogWindowWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..2476f6a464d95749956103505380000576835aec
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/LogWindowWrapper.java
@@ -0,0 +1,28 @@
+package se.leap.bitmaskclient;
+
+import android.content.*;
+
+import de.blinkt.openvpn.activities.*;
+
+public class LogWindowWrapper {
+    private static LogWindowWrapper instance;
+
+    private static String TAG = LogWindowWrapper.class.getName();
+    private Context context;
+
+    public LogWindowWrapper(Context context) {
+        this.context = context;
+    }
+
+    public void showLog() {
+        Intent startLW = new Intent(context, LogWindow.class);
+        startLW.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(startLW);
+    }
+
+    public static LogWindowWrapper getInstance(Context context) {
+        if(instance == null)
+            instance = new LogWindowWrapper(context);
+        return instance;
+    }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java
index a030927dbf323f2b959b29eb250aebaeb589babf..559b47d1851dfd8554be5b93072fad3eb3efffc0 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Provider.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java
@@ -30,8 +30,8 @@ import java.util.*;
  */
 public final class Provider implements Parcelable {
 
-    private JSONObject definition; // Represents our Provider's provider.json
-    private URL main_url;
+    private JSONObject definition = new JSONObject(); // Represents our Provider's provider.json
+    private DefaultedURL main_url = new DefaultedURL();
     private String certificate_pin = "";
 
     final public static String
@@ -59,12 +59,14 @@ public final class Provider implements Parcelable {
     private static final String API_TERM_DEFAULT_LANGUAGE = "default_language";
     protected static final String[] API_EIP_TYPES = {"openvpn"};
 
+    public Provider() { }
+
     public Provider(URL main_url) {
-        this.main_url = main_url;
+        this.main_url.setUrl(main_url);
     }
 
     public Provider(URL main_url, String certificate_pin) {
-        this.main_url = main_url;
+        this.main_url.setUrl(main_url);
         this.certificate_pin = certificate_pin;
     }
 
@@ -81,7 +83,7 @@ public final class Provider implements Parcelable {
 
     private Provider(Parcel in) {
         try {
-            main_url = new URL(in.readString());
+            main_url.setUrl(new URL(in.readString()));
             String definition_string = in.readString();
             if (!definition_string.isEmpty())
                 definition = new JSONObject((definition_string));
@@ -90,6 +92,14 @@ public final class Provider implements Parcelable {
         }
     }
 
+    public boolean isConfigured() {
+        return !main_url.isDefault() && definition.length() > 0;
+    }
+
+    protected void setUrl(URL url) {
+        main_url.setUrl(url);
+    }
+
     protected void define(JSONObject provider_json) {
         definition = provider_json;
     }
@@ -99,16 +109,16 @@ public final class Provider implements Parcelable {
     }
 
     protected String getDomain() {
-        return main_url.getHost();
+        return main_url.getDomain();
     }
 
-    protected URL mainUrl() {
+    protected DefaultedURL mainUrl() {
         return main_url;
     }
 
     protected String certificatePin() { return certificate_pin; }
 
-    protected String getName() {
+    public String getName() {
         // Should we pass the locale in, or query the system here?
         String lang = Locale.getDefault().getLanguage();
         String name = "";
@@ -118,7 +128,7 @@ public final class Provider implements Parcelable {
             else throw new JSONException("Provider not defined");
         } catch (JSONException e) {
             if (main_url != null) {
-                String host = main_url.getHost();
+                String host = main_url.getDomain();
                 name = host.substring(0, host.indexOf("."));
             }
         }
@@ -181,7 +191,8 @@ public final class Provider implements Parcelable {
 
     @Override
     public void writeToParcel(Parcel parcel, int i) {
-        parcel.writeString(main_url.toString());
+        if(main_url != null)
+            parcel.writeString(main_url.toString());
         if (definition != null)
             parcel.writeString(definition.toString());
     }
@@ -190,7 +201,7 @@ public final class Provider implements Parcelable {
     public boolean equals(Object o) {
         if (o instanceof Provider) {
             Provider p = (Provider) o;
-            return p.mainUrl().getHost().equals(mainUrl().getHost());
+            return p.mainUrl().getDomain().equals(mainUrl().getDomain());
         } else return false;
     }
 
@@ -206,6 +217,6 @@ public final class Provider implements Parcelable {
 
     @Override
     public int hashCode() {
-        return mainUrl().getHost().hashCode();
+        return mainUrl().getDomain().hashCode();
     }
 }
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..0e4cfe8a3d3231418d3ed5c010f3792552a0c668
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java
@@ -0,0 +1,45 @@
+package se.leap.bitmaskclient;
+
+import android.content.*;
+import android.os.*;
+
+import org.jetbrains.annotations.*;
+
+public class ProviderAPICommand {
+    private static Context context;
+
+    private static String action;
+    private static Bundle parameters;
+    private static ResultReceiver result_receiver;
+
+    public static void initialize(Context context) {
+        ProviderAPICommand.context = context;
+    }
+
+    private static boolean isInitialized() {
+        return context != null;
+    }
+
+    public static void execute(Bundle parameters, @NotNull String action, @NotNull ResultReceiver result_receiver) throws IllegalStateException {
+        if(!isInitialized()) throw new IllegalStateException();
+
+        ProviderAPICommand.action = action;
+        ProviderAPICommand.parameters = parameters;
+        ProviderAPICommand.result_receiver = result_receiver;
+
+        Intent intent = setUpIntent();
+        context.startService(intent);
+    }
+
+    private static Intent setUpIntent() {
+        Intent command = new Intent(context, ProviderAPI.class);
+
+        command.setAction(action);
+        command.putExtra(ProviderAPI.PARAMETERS, parameters);
+        command.putExtra(ProviderAPI.RECEIVER_KEY, result_receiver);
+
+        return command;
+    }
+
+
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java
index 533e5cafbbdee96bec5e9a9d6912bc1ebeb20ff4..9b880f89da38bf85263c0257a12e75ebc070fbd1 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java
@@ -26,8 +26,9 @@ import android.os.*;
 public class ProviderAPIResultReceiver extends ResultReceiver {
     private Receiver mReceiver;
 
-    public ProviderAPIResultReceiver(Handler handler) {
+    public ProviderAPIResultReceiver(Handler handler, Receiver receiver) {
         super(handler);
+        setReceiver(receiver);
         // TODO Auto-generated constructor stub
     }
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
index 220a71c8d537a30a11b1b2cef472f8c5e5d36059..13ef9b805c184fcf03e0da07f157a8d8f6956f8d 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
@@ -28,7 +28,8 @@ public class ProviderManager implements AdapteeCollection<Provider> {
         if (instance == null)
             instance = new ProviderManager(assets_manager);
 
-        instance.addCustomProviders(external_files_dir);
+        if(external_files_dir != null)
+            instance.addCustomProviders(external_files_dir);
         return instance;
     }
 
@@ -120,7 +121,8 @@ public class ProviderManager implements AdapteeCollection<Provider> {
     public Set<Provider> providers() {
         Set<Provider> all_providers = new HashSet<Provider>();
         all_providers.addAll(default_providers);
-        all_providers.addAll(custom_providers);
+        if(custom_providers != null)
+            all_providers.addAll(custom_providers);
         return all_providers;
     }
 
@@ -140,25 +142,27 @@ public class ProviderManager implements AdapteeCollection<Provider> {
     }
 
     @Override
-    public void add(Provider element) {
+    public boolean add(Provider element) {
         if (!default_providers.contains(element))
-            custom_providers.add(element);
+            return custom_providers.add(element);
+        else return true;
     }
 
     @Override
-    public void remove(Provider element) {
-        custom_providers.remove(element);
+    public boolean remove(Object element) {
+        return custom_providers.remove(element);
     }
 
     @Override
-    public void addAll(Collection<Provider> elements) {
-        custom_providers.addAll(elements);
+    public boolean addAll(Collection<? extends Provider> elements) {
+        return custom_providers.addAll(elements);
     }
 
     @Override
-    public void removeAll(Collection<Provider> elements) {
-        custom_providers.removeAll(elements);
-        default_providers.removeAll(elements);
+    public boolean removeAll(Collection<?> elements) {
+        if(!elements.getClass().equals(Provider.class))
+            return false;
+        return default_providers.removeAll(elements) || custom_providers.removeAll(elements);
     }
 
     @Override
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java
similarity index 70%
rename from app/src/main/java/se/leap/bitmaskclient/EipFragment.java
rename to app/src/main/java/se/leap/bitmaskclient/VpnFragment.java
index bfa67815d680419a3d789ad6c7ff52d2fb04cf90..2e3d752470858e573702532de44836cfe14acf5a 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java
@@ -19,7 +19,6 @@ package se.leap.bitmaskclient;
 import android.app.*;
 import android.content.*;
 import android.os.*;
-import android.util.*;
 import android.view.*;
 import android.widget.*;
 
@@ -29,26 +28,24 @@ import java.util.*;
 
 import butterknife.*;
 import de.blinkt.openvpn.activities.*;
+import mbanje.kurt.fabbutton.*;
 import se.leap.bitmaskclient.eip.*;
 
-public class EipFragment extends Fragment implements Observer {
+public class VpnFragment extends Fragment implements Observer {
 
-    public static String TAG = EipFragment.class.getSimpleName();
+    public static String TAG = VpnFragment.class.getSimpleName();
 
-    protected static final String IS_PENDING = TAG + ".is_pending";
+    public static final String IS_PENDING = TAG + ".is_pending";
     protected static final String IS_CONNECTED = TAG + ".is_connected";
-    protected static final String STATUS_MESSAGE = TAG + ".status_message";
     public static final String START_ON_BOOT = "start on boot";
 
-    @InjectView(R.id.eipSwitch)
-    Switch eip_switch;
-    @InjectView(R.id.status_message)
-    TextView status_message;
-    @InjectView(R.id.eipProgress)
-    ProgressBar progress_bar;
+    @InjectView(R.id.vpn_Status_Image)
+    FabButton vpn_status_image;
+    @InjectView(R.id.vpn_main_button)
+    Button main_button;
 
     private static Dashboard dashboard;
-    private static EIPReceiver mEIPReceiver;
+    private static EIPReceiver eip_receiver;
     private static EipStatus eip_status;
     private boolean wants_to_connect;
 
@@ -56,7 +53,10 @@ public class EipFragment extends Fragment implements Observer {
         super.onAttach(activity);
 
         dashboard = (Dashboard) activity;
-        dashboard.providerApiCommand(Bundle.EMPTY, 0, ProviderAPI.DOWNLOAD_EIP_SERVICE);
+        ProviderAPIResultReceiver provider_api_receiver = new ProviderAPIResultReceiver(new Handler(), dashboard);
+
+        if(eip_receiver != null)
+            ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.DOWNLOAD_EIP_SERVICE, provider_api_receiver);
     }
 
     @Override
@@ -64,7 +64,7 @@ public class EipFragment extends Fragment implements Observer {
         super.onCreate(savedInstanceState);
         eip_status = EipStatus.getInstance();
         eip_status.addObserver(this);
-        mEIPReceiver = new EIPReceiver(new Handler());
+        eip_receiver = new EIPReceiver(new Handler());
     }
 
     @Override
@@ -72,9 +72,6 @@ public class EipFragment extends Fragment implements Observer {
         View view = inflater.inflate(R.layout.eip_service_fragment, container, false);
         ButterKnife.inject(this, view);
 
-        if (eip_status.isConnecting())
-            eip_switch.setVisibility(View.VISIBLE);
-
         Bundle arguments = getArguments();
         if (arguments != null && arguments.containsKey(START_ON_BOOT) && arguments.getBoolean(START_ON_BOOT))
             startEipFromScratch();
@@ -88,8 +85,6 @@ public class EipFragment extends Fragment implements Observer {
             eip_status.setConnecting();
         else if (savedInstanceState.getBoolean(IS_CONNECTED))
             eip_status.setConnectedOrDisconnected();
-        else
-            status_message.setText(savedInstanceState.getString(STATUS_MESSAGE));
     }
 
     @Override
@@ -103,25 +98,20 @@ public class EipFragment extends Fragment implements Observer {
     public void onSaveInstanceState(Bundle outState) {
         outState.putBoolean(IS_PENDING, eip_status.isConnecting());
         outState.putBoolean(IS_CONNECTED, eip_status.isConnected());
-        outState.putString(STATUS_MESSAGE, status_message.getText().toString());
         super.onSaveInstanceState(outState);
     }
 
     protected void saveStatus() {
-        boolean is_on = eip_switch.isChecked();
+        boolean is_on = eip_status.isConnected() || eip_status.isConnecting();
         Dashboard.preferences.edit().putBoolean(Dashboard.START_ON_BOOT, is_on).commit();
     }
 
-    void handleNewVpnCertificate() {
-        handleSwitch(!eip_switch.isEnabled());
-    }
-
-    @OnCheckedChanged(R.id.eipSwitch)
-    void handleSwitch(boolean isChecked) {
-        if (isChecked)
-            handleSwitchOn();
-        else
+    @OnClick(R.id.vpn_main_button)
+    void handleIcon() {
+        if (eip_status.isConnected() || eip_status.isConnecting())
             handleSwitchOff();
+        else
+            handleSwitchOn();
 
         saveStatus();
     }
@@ -155,23 +145,22 @@ public class EipFragment extends Fragment implements Observer {
         } else if (eip_status.isConnected()) {
             askToStopEIP();
         } else
-            setDisconnectedUI();
+            updateIcon();
     }
 
     private void askPendingStartCancellation() {
         AlertDialog.Builder alertBuilder = new AlertDialog.Builder(dashboard);
         alertBuilder.setTitle(dashboard.getString(R.string.eip_cancel_connect_title))
                 .setMessage(dashboard.getString(R.string.eip_cancel_connect_text))
-                .setPositiveButton((R.string.yes), new DialogInterface.OnClickListener() {
+                .setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
                         askToStopEIP();
                     }
                 })
-                .setNegativeButton(dashboard.getString(R.string.no), new DialogInterface.OnClickListener() {
+                .setNegativeButton(dashboard.getString(android.R.string.no), new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
-                        eip_switch.setChecked(true);
                     }
                 })
                 .show();
@@ -180,14 +169,7 @@ public class EipFragment extends Fragment implements Observer {
     public void startEipFromScratch() {
         wants_to_connect = false;
         eip_status.setConnecting();
-        progress_bar.setVisibility(View.VISIBLE);
-        eip_switch.setVisibility(View.VISIBLE);
-        String status = dashboard.getString(R.string.eip_status_start_pending);
-        status_message.setText(status);
 
-        if (!eip_switch.isChecked()) {
-            eip_switch.setChecked(true);
-        }
         saveStatus();
         eipCommand(Constants.ACTION_START_EIP);
     }
@@ -205,12 +187,6 @@ public class EipFragment extends Fragment implements Observer {
     }
 
     protected void stopEipIfPossible() {
-
-        hideProgressBar();
-
-        String message = dashboard.getString(R.string.eip_state_not_connected);
-        status_message.setText(message);
-
         eipCommand(Constants.ACTION_STOP_EIP);
     }
 
@@ -218,16 +194,15 @@ public class EipFragment extends Fragment implements Observer {
         AlertDialog.Builder alertBuilder = new AlertDialog.Builder(dashboard);
         alertBuilder.setTitle(dashboard.getString(R.string.eip_cancel_connect_title))
                 .setMessage(dashboard.getString(R.string.eip_warning_browser_inconsistency))
-                .setPositiveButton((R.string.yes), new DialogInterface.OnClickListener() {
+                .setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
                         stopEipIfPossible();
                     }
                 })
-                .setNegativeButton(dashboard.getString(R.string.no), new DialogInterface.OnClickListener() {
+                .setNegativeButton(dashboard.getString(android.R.string.no), new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
-                        eip_switch.setChecked(true);
                     }
                 })
                 .show();
@@ -247,7 +222,7 @@ public class EipFragment extends Fragment implements Observer {
         // TODO validate "action"...how do we get the list of intent-filters for a class via Android API?
         Intent vpn_intent = new Intent(dashboard.getApplicationContext(), EIP.class);
         vpn_intent.setAction(action);
-        vpn_intent.putExtra(Constants.RECEIVER_TAG, mEIPReceiver);
+        vpn_intent.putExtra(Constants.RECEIVER_TAG, eip_receiver);
         dashboard.startService(vpn_intent);
     }
 
@@ -266,69 +241,42 @@ public class EipFragment extends Fragment implements Observer {
     }
 
     private void handleNewState(EipStatus eip_status) {
-        if (eip_status.wantsToDisconnect())
-            setDisconnectedUI();
-        else if (eip_status.isConnecting())
-            setInProgressUI(eip_status);
-        else if (eip_status.isConnected())
-            setConnectedUI();
-        else if (eip_status.isDisconnected() && !eip_status.isConnecting())
-            setDisconnectedUI();
-    }
+        Context context = dashboard.getApplicationContext();
+        String error = eip_status.lastError(5, context);
 
-    private void setConnectedUI() {
-        hideProgressBar();
-        adjustSwitch();
-        status_message.setText(dashboard.getString(R.string.eip_state_connected));
-    }
-
-    private void setDisconnectedUI() {
-        hideProgressBar();
-        adjustSwitch();
-        if (eip_status.errorInLast(5, dashboard.getApplicationContext())
-                && !status_message.getText().toString().equalsIgnoreCase(dashboard.getString(R.string.eip_state_not_connected))) {
+        if (!error.isEmpty()) {
             dashboard.showLog();
             VoidVpnService.stop();
         }
-        status_message.setText(dashboard.getString(R.string.eip_state_not_connected));
+        updateIcon();
+        updateButton();
     }
 
-    private void adjustSwitch() {
+    private void updateIcon() {
         if (eip_status.isConnected() || eip_status.isConnecting()) {
-            if (!eip_switch.isChecked()) {
-                eip_switch.setChecked(true);
+            if(eip_status.isConnecting()) {
+                vpn_status_image.showProgress(true);
+                vpn_status_image.setIcon(R.drawable.ic_stat_vpn_empty_halo, R.drawable.ic_stat_vpn_empty_halo);
+            } else {
+                vpn_status_image.showProgress(false);
+                vpn_status_image.setIcon(R.drawable.ic_stat_vpn, R.drawable.ic_stat_vpn);
             }
         } else {
-
-            if (eip_switch.isChecked()) {
-                eip_switch.setChecked(false);
-            }
+            vpn_status_image.setIcon(R.drawable.ic_stat_vpn_offline, R.drawable.ic_stat_vpn_offline);
+            vpn_status_image.showProgress(false);
         }
     }
 
-    private void setInProgressUI(EipStatus eip_status) {
-        int localizedResId = eip_status.getLocalizedResId();
-        String logmessage = eip_status.getLogMessage();
-        String prefix = dashboard.getString(localizedResId);
-
-        showProgressBar();
-        status_message.setText(prefix + " " + logmessage);
-        adjustSwitch();
-    }
-
-    private void updatingCertificateUI() {
-        showProgressBar();
-        status_message.setText(getString(R.string.updating_certificate_message));
-    }
-
-    private void showProgressBar() {
-        if (progress_bar != null)
-            progress_bar.setVisibility(View.VISIBLE);
-    }
-
-    private void hideProgressBar() {
-        if (progress_bar != null)
-            progress_bar.setVisibility(View.GONE);
+    private void updateButton() {
+        if (eip_status.isConnected() || eip_status.isConnecting()) {
+            if(eip_status.isConnecting()) {
+                main_button.setText(dashboard.getString(android.R.string.cancel));
+            } else {
+                main_button.setText(dashboard.getString(R.string.vpn_button_turn_off));
+            }
+        } else {
+            main_button.setText(dashboard.getString(R.string.vpn_button_turn_on));
+        }
     }
 
     protected class EIPReceiver extends ResultReceiver {
@@ -371,7 +319,6 @@ public class EipFragment extends Fragment implements Observer {
                     case Activity.RESULT_OK:
                         break;
                     case Activity.RESULT_CANCELED:
-                        updatingCertificateUI();
                         dashboard.downloadVpnCertificate();
                         break;
                 }
@@ -391,6 +338,6 @@ public class EipFragment extends Fragment implements Observer {
 
 
     public static EIPReceiver getReceiver() {
-        return mEIPReceiver;
+        return eip_receiver;
     }
 }
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
index beed794879732fad2f362ccd5ad131f5b300bd45..9ff7f1afd7a678e70ebd6c544272c0804a31a111 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
@@ -96,7 +96,7 @@ public final class EIP extends IntentService {
 
         gateway = gateways_manager.select();
         if (gateway != null && gateway.getProfile() != null) {
-            mReceiver = EipFragment.getReceiver();
+            mReceiver = VpnFragment.getReceiver();
             launchActiveGateway();
             tellToReceiver(ACTION_START_EIP, Activity.RESULT_OK);
         } else
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 b7f952779b9631d6e627e7cdf6f17699f37e8a63..4bfef1cb6bd41bfe6ced6220689f030905ef884b 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java
@@ -31,7 +31,7 @@ public class EipStatus extends Observable implements VpnStatus.StateListener {
             wants_to_disconnect = false,
             is_connecting = false;
 
-
+    int last_error_line = 0;
     private String state, log_message;
     private int localized_res_id;
 
@@ -137,18 +137,30 @@ public class EipStatus extends Observable implements VpnStatus.StateListener {
     }
 
     public boolean errorInLast(int lines, Context context) {
-        boolean result = false;
+        return !lastError(lines, context).isEmpty();
+    }
+
+    public String lastError(int lines, Context context) {
+        String error = "";
+
         String[] error_keywords = {"error", "ERROR", "fatal", "FATAL"};
 
         VpnStatus.LogItem[] log = VpnStatus.getlogbuffer();
+        if(log.length < last_error_line)
+            last_error_line = 0;
         String message = "";
         for (int i = 1; i <= lines && log.length > i; i++) {
-            message = log[log.length - i].getString(context);
+            int line = log.length - i;
+            VpnStatus.LogItem log_item = log[line];
+            message = log_item.getString(context);
             for (int j = 0; j < error_keywords.length; j++)
-                if (message.contains(error_keywords[j]))
-                    result = true;
+                if (message.contains(error_keywords[j]) && line > last_error_line) {
+                    error = message;
+                    last_error_line = line;
+                }
         }
-        return result;
+
+        return error;
     }
 
     @Override
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
index 1c64328e77d5dbc4ff62fd9ec666aa34b86792e3..f41049c540ec4c6df89ff95550648f9929d3740d 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -16,19 +16,27 @@
  */
 package se.leap.bitmaskclient.eip;
 
-import android.content.*;
+import android.content.Context;
+import android.content.SharedPreferences;
 
-import com.google.gson.*;
-import com.google.gson.reflect.*;
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.reflect.TypeToken;
 
-import org.json.*;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
 
-import java.lang.reflect.*;
-import java.util.*;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
 
-import de.blinkt.openvpn.*;
-import de.blinkt.openvpn.core.*;
-import se.leap.bitmaskclient.*;
+import de.blinkt.openvpn.VpnProfile;
+import de.blinkt.openvpn.core.Connection;
+import de.blinkt.openvpn.core.ProfileManager;
+import se.leap.bitmaskclient.Provider;
 
 /**
  * @author parmegv
@@ -65,7 +73,7 @@ public class GatewaysManager {
     }
 
     public void addFromString(String gateways) {
-        List<Gateway> gateways_list = new ArrayList<Gateway>();
+        List<Gateway> gateways_list = new ArrayList<>();
         try {
             gateways_list = new Gson().fromJson(gateways, list_type);
         } catch (JsonSyntaxException e) {
@@ -75,7 +83,6 @@ public class GatewaysManager {
         if (gateways_list != null) {
             for (Gateway gateway : gateways_list)
                 addGateway(gateway);
-            this.gateways.addAll(gateways_list);
         }
     }
 
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 dac92fe2e135d926abe1e981d241172f35cbb485..cbf0fed2928fda34a281724ea3305816f7b92a0c 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java
@@ -50,6 +50,10 @@ public class VoidVpnService extends VpnService {
         closeFd();
     }
 
+    public static boolean isRunning() throws NullPointerException {
+        return thread.isAlive() && fd != null;
+    }
+
     private static void closeFd() {
         try {
             if (fd != null)
diff --git a/app/src/main/java/se/leap/bitmaskclient/userstatus/FabButton.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/FabButton.java
new file mode 100644
index 0000000000000000000000000000000000000000..1bf1847c570e745dec75f43330dc827b0fab466e
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/FabButton.java
@@ -0,0 +1,34 @@
+package se.leap.bitmaskclient.userstatus;
+
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import mbanje.kurt.fabbutton.CircleImageView;
+import se.leap.bitmaskclient.R;
+
+public class FabButton extends mbanje.kurt.fabbutton.FabButton {
+
+
+    public FabButton(Context context) {
+        super(context);
+    }
+
+    public FabButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public FabButton(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected void init(Context context, AttributeSet attrs, int defStyle) {
+        super.init(context, attrs, defStyle);
+        super.init(context, attrs, defStyle);
+    }
+
+    private CircleImageView getImage() {
+        return (CircleImageView) findViewById(R.id.fabbutton_circle);
+    }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java
similarity index 86%
rename from app/src/main/java/se/leap/bitmaskclient/SessionDialog.java
rename to app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java
index 30344ff2d23b2535f756bcb4bccd0aa38259547e..7dbbe05990686130396fe42250b2edf85ff6c093 100644
--- a/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java
@@ -14,7 +14,7 @@
  * You should have received a copy of the GNU General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.userstatus;
 
 import android.app.*;
 import android.content.*;
@@ -23,6 +23,9 @@ import android.view.*;
 import android.widget.*;
 
 import butterknife.*;
+import se.leap.bitmaskclient.VpnFragment;
+import se.leap.bitmaskclient.Provider;
+import se.leap.bitmaskclient.R;
 
 /**
  * Implements the log in dialog, currently without progress dialog.
@@ -56,8 +59,18 @@ public class SessionDialog extends DialogFragment {
 
     private static boolean is_eip_pending = false;
 
-    public SessionDialog() {
-        setArguments(Bundle.EMPTY);
+    public static SessionDialog getInstance(Provider provider, Bundle arguments) {
+        SessionDialog dialog = new SessionDialog();
+        if (provider.getName().equalsIgnoreCase("riseup")) {
+            arguments =
+                    arguments == Bundle.EMPTY ?
+                            new Bundle() : arguments;
+            arguments.putBoolean(SessionDialog.ERRORS.RISEUP_WARNING.toString(), true);
+        }
+        if (arguments != null && !arguments.isEmpty()) {
+            dialog.setArguments(arguments);
+        }
+        return dialog;
     }
 
     public AlertDialog onCreateDialog(Bundle savedInstanceState) {
@@ -68,7 +81,7 @@ public class SessionDialog extends DialogFragment {
         ButterKnife.inject(this, view);
 
         Bundle arguments = getArguments();
-        if (arguments != Bundle.EMPTY) {
+        if (arguments != Bundle.EMPTY && arguments != null) {
             setUp(arguments);
         }
 
@@ -100,7 +113,7 @@ public class SessionDialog extends DialogFragment {
     }
 
     private void setUp(Bundle arguments) {
-        is_eip_pending = arguments.getBoolean(EipFragment.IS_PENDING, false);
+        is_eip_pending = arguments.getBoolean(VpnFragment.IS_PENDING, false);
         if (arguments.containsKey(ERRORS.PASSWORD_INVALID_LENGTH.toString()))
             password_field.setError(getString(R.string.error_not_valid_password_user_message));
         else if (arguments.containsKey(ERRORS.RISEUP_WARNING.toString())) {
@@ -152,8 +165,9 @@ public class SessionDialog extends DialogFragment {
     @Override
     public void onAttach(Activity activity) {
         super.onAttach(activity);
+
         try {
-            interface_with_Dashboard = (SessionDialogInterface) activity;
+            interface_with_Dashboard = (SessionDialogInterface) activity.getFragmentManager().findFragmentById(R.id.user_status_fragment);;
         } catch (ClassCastException e) {
             throw new ClassCastException(activity.toString()
                     + " must implement LogInDialogListener");
diff --git a/app/src/main/java/se/leap/bitmaskclient/User.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/User.java
similarity index 83%
rename from app/src/main/java/se/leap/bitmaskclient/User.java
rename to app/src/main/java/se/leap/bitmaskclient/userstatus/User.java
index f3d3b8b199a993bab2b67e342fe0a7ab0ab598e9..64ce0629ce8eb87767b29756ae96dcc249bbdc00 100644
--- a/app/src/main/java/se/leap/bitmaskclient/User.java
+++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/User.java
@@ -14,16 +14,18 @@
  * You should have received a copy of the GNU General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.userstatus;
+
+import se.leap.bitmaskclient.LeapSRPSession;
 
 public class User {
-    private static String user_name = "";
+    private static String user_name;
     private static User user;
-    public static int DEFAULT_CONJUGATION_PERSON = 1;
 
-    public static User init() {
+    public static User init(String default_username) {
         if (user == null) {
             user = new User();
+            user.setUserName(default_username);
         }
         return user;
     }
diff --git a/app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatus.java
similarity index 83%
rename from app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java
rename to app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatus.java
index 28c7ecc7e2f9569dc2cf7de5d670dbe5fa265476..edfed8d65311b27539555e0e67c7bfc25831b2f9 100644
--- a/app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java
+++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatus.java
@@ -14,15 +14,17 @@
  * You should have received a copy of the GNU General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.userstatus;
 
 import android.content.res.*;
 
 import java.util.*;
 
-public class UserSessionStatus extends Observable {
-    public static String TAG = UserSessionStatus.class.getSimpleName();
-    private static UserSessionStatus current_status;
+import se.leap.bitmaskclient.R;
+
+public class UserStatus extends Observable {
+    public static String TAG = UserStatus.class.getSimpleName();
+    private static UserStatus current_status;
     private static Resources resources;
 
     public enum SessionStatus {
@@ -56,17 +58,17 @@ public class UserSessionStatus extends Observable {
         }
     }
 
-    private static SessionStatus session_status = SessionStatus.NOT_LOGGED_IN;
+    private static SessionStatus session_status = SessionStatus.LOGGED_OUT;
 
-    public static UserSessionStatus getInstance(Resources resources) {
+    public static UserStatus getInstance(Resources resources) {
         if (current_status == null) {
-            current_status = new UserSessionStatus(resources);
+            current_status = new UserStatus(resources);
         }
         return current_status;
     }
 
-    private UserSessionStatus(Resources resources) {
-        UserSessionStatus.resources = resources;
+    private UserStatus(Resources resources) {
+        UserStatus.resources = resources;
     }
 
     private void sessionStatus(SessionStatus session_status) {
@@ -82,6 +84,14 @@ public class UserSessionStatus extends Observable {
                 || session_status == SessionStatus.LOGGING_OUT;
     }
 
+    public boolean isLoggedIn() {
+        return session_status == SessionStatus.LOGGED_IN;
+    }
+
+    public boolean isLoggedOut() {
+        return session_status == SessionStatus.LOGGED_OUT;
+    }
+
     public static void updateStatus(SessionStatus session_status, Resources resources) {
         current_status = getInstance(resources);
         current_status.sessionStatus(session_status);
@@ -93,7 +103,7 @@ public class UserSessionStatus extends Observable {
     public String toString() {
         String user_session_status = User.userName();
 
-        String default_username = resources.getString(R.string.default_user, "");
+        String default_username = resources.getString(R.string.default_username, "");
         if(user_session_status.isEmpty() && !default_username.equalsIgnoreCase("null")) user_session_status = default_username;
         user_session_status += " " + session_status.toString();
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java
new file mode 100644
index 0000000000000000000000000000000000000000..f670553f55b918d64123acafec3a1c142ef91098
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java
@@ -0,0 +1,181 @@
+package se.leap.bitmaskclient.userstatus;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Observable;
+import java.util.Observer;
+
+import butterknife.ButterKnife;
+import butterknife.InjectView;
+import butterknife.OnClick;
+import se.leap.bitmaskclient.Dashboard;
+import se.leap.bitmaskclient.Provider;
+import se.leap.bitmaskclient.ProviderAPI;
+import se.leap.bitmaskclient.ProviderAPICommand;
+import se.leap.bitmaskclient.ProviderAPIResultReceiver;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.eip.EipStatus;
+
+public class UserStatusFragment extends Fragment implements Observer, SessionDialog.SessionDialogInterface {
+
+    public static String TAG = UserStatusFragment.class.getSimpleName();
+    private static Dashboard dashboard;
+    private ProviderAPIResultReceiver providerAPI_result_receiver;
+
+    @InjectView(R.id.user_status_username)
+    TextView username;
+    @InjectView(R.id.user_status_icon)
+    FabButton icon;
+    @InjectView(R.id.user_status_button)
+    Button button;
+
+    private UserStatus status;
+    private boolean allows_registration = false;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        status = UserStatus.getInstance(getResources());
+        status.addObserver(this);
+    }
+
+    @Override
+    public void onSaveInstanceState(@NotNull Bundle outState) {
+        if (username != null && username.getVisibility() == TextView.VISIBLE)
+            outState.putSerializable(UserStatus.TAG, status.sessionStatus());
+
+        super.onSaveInstanceState(outState);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View view = inflater.inflate(R.layout.user_session_fragment, container, false);
+        ButterKnife.inject(this, view);
+
+        Bundle arguments = getArguments();
+        allows_registration = arguments.getBoolean(Provider.ALLOW_REGISTRATION);
+        handleNewStatus(status);
+
+        return view;
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        dashboard = (Dashboard) activity;
+
+        providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler(), dashboard);
+    }
+
+    public void restoreSessionStatus(Bundle savedInstanceState) {
+        if (savedInstanceState != null)
+            if (savedInstanceState.containsKey(UserStatus.TAG)) {
+                UserStatus.SessionStatus status = (UserStatus.SessionStatus) savedInstanceState.getSerializable(UserStatus.TAG);
+                this.status.updateStatus(status, getResources());
+            }
+    }
+
+    @OnClick(R.id.user_status_button)
+    public void handleButton() {
+        android.util.Log.d(TAG, status.toString());
+        if(status.isLoggedIn())
+            logOut();
+        else if(status.isLoggedOut())
+            dashboard.sessionDialog(Bundle.EMPTY);
+        else if(status.inProgress())
+            cancelLoginOrSignup();
+    }
+
+    @Override
+    public void update(Observable observable, Object data) {
+        if (observable instanceof UserStatus) {
+            final UserStatus status = (UserStatus) observable;
+            dashboard.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    handleNewStatus(status);
+                }
+            });
+        }
+    }
+
+    private void handleNewStatus(UserStatus status) {
+        this.status = status;
+        if (allows_registration) {
+            if (this.status.inProgress())
+                showUserSessionProgressBar();
+            else
+                hideUserSessionProgressBar();
+            changeMessage();
+            updateButton();
+        }
+    }
+
+    private void showUserSessionProgressBar() {
+        icon.showProgress(true);
+    }
+
+    private void hideUserSessionProgressBar() {
+        icon.showProgress(false);
+    }
+
+    private void changeMessage() {
+        final String message = User.userName();
+        username.setText(message);
+    }
+
+    private void updateButton() {
+        if(status.isLoggedIn())
+            button.setText(dashboard.getString(R.string.logout_button));
+        else if(allows_registration) {
+            if (status.isLoggedOut())
+                button.setText(dashboard.getString(R.string.login_button));
+            else if (status.inProgress())
+                button.setText(dashboard.getString(android.R.string.cancel));
+        }
+    }
+
+
+    @Override
+    public void signUp(String username, String password) {
+        User.setUserName(username);
+        Bundle parameters = bundlePassword(password);
+        ProviderAPICommand.execute(parameters, ProviderAPI.SIGN_UP, providerAPI_result_receiver);
+    }
+
+    @Override
+    public void logIn(String username, String password) {
+        User.setUserName(username);
+        Bundle parameters = bundlePassword(password);
+        ProviderAPICommand.execute(parameters, ProviderAPI.LOG_IN, providerAPI_result_receiver);
+    }
+
+    public void logOut() {
+        android.util.Log.d(TAG, "Log out");
+        ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.LOG_OUT, providerAPI_result_receiver);
+    }
+
+    public void cancelLoginOrSignup() {
+        EipStatus.getInstance().setConnectedOrDisconnected();
+    }
+
+    private Bundle bundlePassword(String password) {
+        Bundle parameters = new Bundle();
+        if (!password.isEmpty())
+            parameters.putString(SessionDialog.PASSWORD, password);
+        return parameters;
+    }
+}
diff --git a/app/src/main/res/drawable-hdpi/ic_account_circle.png b/app/src/main/res/drawable-hdpi/ic_account_circle.png
new file mode 100644
index 0000000000000000000000000000000000000000..60e50a034f37d321cd100410e3c97455cdc9ec1d
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_account_circle.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_account_circle.png b/app/src/main/res/drawable-mdpi/ic_account_circle.png
new file mode 100644
index 0000000000000000000000000000000000000000..9cc9f0b5e594e7bc61bbb284034d62d7eb13fdae
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_account_circle.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_account_circle.png b/app/src/main/res/drawable-xhdpi/ic_account_circle.png
new file mode 100644
index 0000000000000000000000000000000000000000..8af556048fc6f8501e1000800b877a22c4000cc0
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_account_circle.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_account_circle.png b/app/src/main/res/drawable-xxhdpi/ic_account_circle.png
new file mode 100644
index 0000000000000000000000000000000000000000..6e81a76b24e3c5bbbb33f524381338501c6d9dc2
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_account_circle.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_account_circle.png b/app/src/main/res/drawable-xxxhdpi/ic_account_circle.png
new file mode 100644
index 0000000000000000000000000000000000000000..9511ae3afb1433d681ecb7d7b4d2915b8955eedb
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_account_circle.png differ
diff --git a/app/src/main/res/layout-xlarge/dashboard.xml b/app/src/main/res/layout-xlarge/dashboard.xml
index 268bd3f95e8ff4a32fa2318b29c92ac3d85cf110..3c93a04c2d02115ac15d06c9fd832da667b9bcc8 100644
--- a/app/src/main/res/layout-xlarge/dashboard.xml
+++ b/app/src/main/res/layout-xlarge/dashboard.xml
@@ -5,80 +5,45 @@
     android:layout_height="match_parent"
     android:orientation="vertical"
     android:layout_marginLeft="10sp"
+    android:layout_marginStart="10sp"
     android:layout_marginTop="10sp"
     tools:context=".Dashboard" >
-    
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="42dp"
-        android:background="?android:attr/selectableItemBackground" >
-    
-        <LinearLayout
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:gravity="center_vertical"
-            android:orientation="vertical"
-            android:paddingLeft="10dp" >
-
-            <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                android:singleLine="true"
-                android:text="@string/provider_label"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:textSize="32sp" />
-
-        </LinearLayout>
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:gravity="center_vertical"
-            android:orientation="vertical"
-            android:paddingLeft="32dp" >
 
-            <TextView
-                android:id="@+id/providerName"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                android:singleLine="true"
-                android:text="@string/provider_label_none"
-                android:textAppearance="?android:attr/textAppearanceMedium" />
-
-        </LinearLayout>
-    </LinearLayout>
+    <TextView
+        android:id="@+id/providerName"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="32dp"
+        android:layout_marginStart="32dp"
+        android:textSize="48sp"
+        android:ellipsize="marquee"
+        android:gravity="center_vertical"
+        android:text="@string/provider_label_none"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:paddingLeft="32dp">
-      <ProgressBar
-          android:id="@+id/user_session_status_progress"
-          android:layout_width="wrap_content"
-          android:layout_height="fill_parent"
-          android:indeterminate="true"
-          android:visibility="gone"/>
-      <TextView
-          android:id="@+id/user_session_status"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:textSize="18sp"
-          android:layout_marginLeft="10dp"
-          android:ellipsize="marquee"
-          android:singleLine="true"
-          android:textAppearance="?android:attr/textAppearanceMedium"
-          />
+        android:layout_marginLeft="32dp"
+        android:layout_marginStart="32dp">
+        <ProgressBar
+            android:id="@+id/user_session_status_progress"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:indeterminate="true"
+            android:visibility="gone"/>
+        <TextView
+            android:id="@+id/user_session_status"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="18sp"
+            android:layout_marginLeft="10dp"
+            android:layout_marginStart="10dp"
+            android:ellipsize="marquee"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            />
     </LinearLayout>
-    
-    <View
-        android:layout_width="wrap_content"
-        android:layout_height="1dp"
-        android:layout_marginBottom="7dp"
-        android:background="@android:drawable/divider_horizontal_bright" />
 
     <LinearLayout
         android:id="@+id/servicesCollection"
diff --git a/app/src/main/res/layout-xlarge/eip_service_fragment.xml b/app/src/main/res/layout-xlarge/eip_service_fragment.xml
index 38b6aca314e0617b54be7221bc43f5cead139572..a9f01fb88f1c2a9c6c5a7c7fe631672fe75a32bf 100644
--- a/app/src/main/res/layout-xlarge/eip_service_fragment.xml
+++ b/app/src/main/res/layout-xlarge/eip_service_fragment.xml
@@ -3,54 +3,53 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_marginTop="10dp"
-    android:layout_marginLeft="20dp" >
+    android:layout_marginLeft="20dp"
+    android:layout_marginStart="20dp">
 
     <TextView
         android:id="@+id/eipLabel"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
         android:layout_marginLeft="10dp"
-        android:clickable="true"
+        android:layout_marginStart="10dp"
+        android:layout_marginTop="12dp"
+        android:layout_marginBottom="12dp"
         android:text="@string/eip_service_label"
         android:textAppearance="?android:attr/textAppearanceLarge"
-        android:textSize="26sp" />
+        android:textSize="24sp"/>
 
-    <Switch
-        android:id="@+id/eipSwitch"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentRight="true"
-        android:layout_alignParentTop="true"
-        android:layout_marginRight="10dp"
-        android:height="26dp"/>
-    
-    <ProgressBar 
-        android:id="@+id/eipProgress"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@android:style/Widget.Holo.ProgressBar.Horizontal"
-        android:indeterminate="true"
-        android:visibility="gone"
-        android:layout_below="@id/eipLabel"
-        android:layout_marginLeft="15dp"
-        android:layout_marginRight="15dp" />
 
-    <TextView
-        android:id="@+id/status_message"
+    <LinearLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:orientation="horizontal"
         android:layout_below="@+id/eipLabel"
-        android:paddingBottom="10dp"
-        android:paddingLeft="10dp"
-        android:paddingRight="10dp"
-        android:paddingTop="10dp"
-        android:layout_alignParentLeft="true"
-        android:layout_centerVertical="true"
-        android:clickable="true"
-        android:text="@string/eip_state_not_connected"
-        android:textSize="16sp" />
+        android:layout_centerInParent="true">
 
+        <Button
+            android:id="@+id/vpn.main.button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="24dp"
+            android:layout_marginLeft="24dp"
+            android:textSize="32sp"
+            />
 
+        <view
+            android:id="@+id/vpn.Status.Image"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:color="@android:color/holo_blue_dark"
+            class="mbanje.kurt.fabbutton.FabButton"
+            android:layout_gravity="center"
+            android:visibility="visible"
+            android:indeterminate="true"
+            android:max="100"
+            fbb_autoStart="true"
+            fbb_progressColor="#ff170aff"
+            fbb_progressWidthRatio="0.1"
+            android:layout_marginStart="24dp"
+            android:layout_marginLeft="24dp"
+            />
+    </LinearLayout>
 </RelativeLayout>
diff --git a/app/src/main/res/layout-xlarge/user_session_fragment.xml b/app/src/main/res/layout-xlarge/user_session_fragment.xml
new file mode 100644
index 0000000000000000000000000000000000000000..30969219d37176105e44426e49e59d9f4b8d5e17
--- /dev/null
+++ b/app/src/main/res/layout-xlarge/user_session_fragment.xml
@@ -0,0 +1,55 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginTop="30dp"
+    android:layout_marginLeft="60dp"
+    android:layout_marginStart="60dp"
+    android:orientation="vertical"
+    tools:context="se.leap.bitmaskclient.userstatus.UserStatusFragment">
+
+    <TextView
+        android:id="@+id/user.status.username"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="30dp"
+        android:layout_marginRight="60dp"
+        android:layout_marginEnd="60dp"
+        android:layout_gravity="center"
+        android:textSize="46sp"
+        android:text="@string/default_username"
+        android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+    <LinearLayout
+        android:id="@+id/user.status.buttonAndIcon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center">
+
+        <Button
+            android:id="@+id/user.status.button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="24sp"
+            />
+
+        <view
+            android:id="@+id/user.status.icon"
+            android:layout_width="56dp"
+            android:layout_height="56dp"
+            android:layout_marginLeft="26dp"
+            android:layout_marginStart="26dp"
+            android:background="@android:color/transparent"
+            android:color="@android:color/holo_blue_dark"
+            class="mbanje.kurt.fabbutton.FabButton"
+            android:layout_gravity="center"
+            android:visibility="visible"
+            android:indeterminate="true"
+            android:max="100"
+            fbb_autoStart="true"
+            fbb_progressColor="#ff170aff"
+            fbb_progressWidthRatio="0.3"
+            />
+
+    </LinearLayout>
+</LinearLayout>
diff --git a/app/src/main/res/layout/dashboard.xml b/app/src/main/res/layout/dashboard.xml
index f4269fe2e65d02149017b1cead82bd1fa14618e3..6a9bbe973fb49c8a35de98777517356a9659ba8c 100644
--- a/app/src/main/res/layout/dashboard.xml
+++ b/app/src/main/res/layout/dashboard.xml
@@ -5,61 +5,30 @@
     android:layout_height="match_parent"
     android:orientation="vertical"
     tools:context=".Dashboard" >
-    
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="40dp"
-        android:background="?android:attr/selectableItemBackground" >
-      
-      <TextView
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-	  android:layout_marginLeft="5dp"
-          android:ellipsize="marquee"
-          android:singleLine="true"
-          android:text="@string/provider_label"
-          android:textAppearance="?android:attr/textAppearanceMedium" />
-      
-      <TextView
-          android:id="@+id/providerName"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:textSize="28sp"
-	  android:layout_marginLeft="10dp"
-          android:ellipsize="marquee"
-          android:singleLine="true"
-          android:text="@string/provider_label_none"
-          android:textAppearance="?android:attr/textAppearanceMedium" />
 
-    </LinearLayout>
+    <TextView
+        android:id="@+id/providerName"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dp"
+        android:layout_marginStart="10dp"
+        android:textSize="26sp"
+        android:ellipsize="marquee"
+        android:gravity="center_vertical"
+        android:singleLine="true"
+        android:text="@string/provider_label_none"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
 
     <LinearLayout
+        android:id="@+id/user.status.fragment"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-        <ProgressBar
-            android:id="@+id/user_session_status_progress"
-            android:layout_width="wrap_content"
-            android:layout_height="fill_parent"
-            android:indeterminate="true"
-            android:visibility="gone"/>
-        <TextView
-            android:id="@+id/user_session_status"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textSize="18sp"
-            android:layout_marginLeft="10dp"
-            android:ellipsize="marquee"
-            android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            />
-    </LinearLayout>
-    
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"/>
+
     <LinearLayout
         android:id="@+id/servicesCollection"
         android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_weight="0.11"
-        android:orientation="vertical" >
-    </LinearLayout>
-
+        android:orientation="vertical" />
 </LinearLayout>
diff --git a/app/src/main/res/layout/eip_service_fragment.xml b/app/src/main/res/layout/eip_service_fragment.xml
index 6adcfab0db8971984964f2646141ce5870fa4d30..06b514d3b12470424e10d999c1913dcde980dc80 100644
--- a/app/src/main/res/layout/eip_service_fragment.xml
+++ b/app/src/main/res/layout/eip_service_fragment.xml
@@ -2,50 +2,49 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:layout_marginTop="10dp" >
+    android:layout_marginTop="10dp">
 
     <TextView
         android:id="@+id/eipLabel"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
         android:layout_marginLeft="10dp"
-        android:clickable="true"
+        android:layout_marginStart="10dp"
+        android:layout_marginTop="12dp"
+        android:layout_marginBottom="12dp"
         android:text="@string/eip_service_label"
         android:textAppearance="?android:attr/textAppearanceMedium" />
 
-    <ProgressBar
-        android:id="@+id/eipProgress"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@android:style/Widget.Holo.ProgressBar.Horizontal"
-        android:indeterminate="true"
-        android:visibility="gone"
-        android:layout_below="@id/eipLabel"
-        android:layout_marginLeft="15dp"
-        android:layout_marginRight="15dp" />
-
-    <TextView
-        android:id="@+id/status_message"
+    <LinearLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_below="@id/eipProgress"
-        android:layout_centerVertical="true"
-        android:paddingTop="5dp"
-        android:paddingBottom="10dp"
-        android:paddingLeft="10dp"
-        android:paddingRight="10dp"
-        android:clickable="true"
-        android:text="@string/eip_state_not_connected" />
+        android:orientation="horizontal"
+        android:layout_below="@+id/eipLabel"
+        android:layout_centerInParent="true">
 
-    <Switch
-        android:id="@+id/eipSwitch"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignTop="@+id/status_message"
-        android:layout_toRightOf="@+id/status_message"
-        android:layout_toEndOf="@+id/status_message" />
+        <Button
+            android:id="@+id/vpn.main.button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="12sp"
+            />
 
+        <view
+            android:id="@+id/vpn.Status.Image"
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:layout_marginLeft="3dp"
+            android:layout_marginStart="3dp"
+            android:color="@android:color/holo_blue_dark"
+            class="mbanje.kurt.fabbutton.FabButton"
+            android:layout_gravity="center"
+            android:visibility="visible"
+            android:indeterminate="true"
+            android:max="100"
+            fbb_autoStart="true"
+            fbb_progressColor="#ff170aff"
+            fbb_progressWidthRatio="0.1"
+            />
+    </LinearLayout>
 </RelativeLayout>
diff --git a/app/src/main/res/layout/user_session_fragment.xml b/app/src/main/res/layout/user_session_fragment.xml
new file mode 100644
index 0000000000000000000000000000000000000000..300683816eadb77eaa218a3008a0a869b07d849b
--- /dev/null
+++ b/app/src/main/res/layout/user_session_fragment.xml
@@ -0,0 +1,43 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginTop="10dp"
+    android:layout_marginLeft="20dp"
+    android:layout_marginStart="20dp"
+    tools:context="se.leap.bitmaskclient.userstatus.UserStatusFragment">
+
+    <TextView
+        android:id="@+id/user.status.username"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="10dp"
+        android:layout_marginRight="15dp"
+        android:layout_marginEnd="20dp"
+        android:textSize="20sp"
+        android:text="@string/default_username"
+        android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+    <Button
+        android:id="@+id/user.status.button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="14sp"
+        />
+
+    <view
+        android:id="@+id/user.status.icon"
+        android:layout_width="50dp"
+        android:layout_height="50dp"
+        android:layout_marginLeft="9dp"
+        android:layout_marginStart="9dp"
+        android:shadowRadius="0"
+        android:src="@drawable/ic_account_circle"
+        android:color="@android:color/transparent"
+        class="se.leap.bitmaskclient.userstatus.FabButton"
+        android:indeterminate="true"
+        fbb_progressColor="@android:color/holo_blue_dark"
+        fbb_progressWidthRatio="0.1"
+        />
+
+</LinearLayout>
diff --git a/app/src/main/res/menu/client_dashboard.xml b/app/src/main/res/menu/client_dashboard.xml
index 9bc39d7ba415487c16e9400e98a3efbf085d3ffc..e0336cc043584966c261fcc0ccd98691686eaa17 100644
--- a/app/src/main/res/menu/client_dashboard.xml
+++ b/app/src/main/res/menu/client_dashboard.xml
@@ -15,15 +15,5 @@
         android:id="@+id/signup_button"
         android:title="@string/signup_button"
         android:visible="false"/>
-    <item
-        android:id="@+id/login_button"
-        android:showAsAction="ifRoom"
-        android:title="@string/login_button"
-        android:visible="false"/>
-    <item
-        android:id="@+id/logout_button"
-        android:showAsAction="ifRoom"
-        android:title="@string/logout_button"
-        android:visible="false"/>
 
 </menu>
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 82ca44e9b0e031a5a92e6980c9bf0e6dc330f511..7f0670b8c34bc2f5b0cc2a2bfc6d8b4b35bce8b6 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -65,13 +65,11 @@
     <string name="eip_cancel_connect_title">¿Abortar conexión?</string>
     <string name="eip_cancel_connect_text">Hay una conexión iniciándose. ¿Quieres cancelarla?</string>
     <string name="eip.warning.browser_inconsistency">Para salvaguardar la privacidad de tu información personal, te recomendamos que después de apagar la VPN cierres la sesión del navegador y abras una sesión privada en él. Gracias.</string>
-    <string name="yes">Sí</string>
-    <string name="no">No</string>
     <string name="eip_state_not_connected">"¡Conexión no protegida!"</string>
     <string name="eip_state_connected">Conexión protegida.</string>
     <string name="provider_problem">Parece que hay un problema con el proveedor.</string>
     <string name="try_another_provider">Prueba con otro proveedor, o contacta con este.</string>
-    <string name="default_user"></string>
+    <string name="default_username">Anónimo</string>
     <string name="logged_in_user_status">inició sesión.</string>
     <string name="logged_out_user_status">cerró la sesión.</string>
     <string name="didnt_log_out_user_status">no cerró la sesión.</string>
@@ -79,5 +77,6 @@
     <string name="logging_in_user_status">está iniciando sesión.</string>
     <string name="logging_out_user_status">está cerrando sesión.</string>
     <string name="signingup_message">está siendo registrado.</string>
-
+    <string name="vpn.button.turn.on">Iniciar</string>
+    <string name="vpn.button.turn.off">Apagar</string>
 </resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index bcfd3a2cceefc0010ae174c4a275f89ef59b966f..7746795eed48c9b755ecfe8ee3d66e25e5c1aefc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -63,13 +63,11 @@
     <string name="eip_cancel_connect_title">Cancel connection?</string>
     <string name="eip_cancel_connect_text">There is a connection attempt in progress.  Do you wish to cancel it?</string>
     <string name="eip.warning.browser_inconsistency">In order to avoid leaking your personal information, please close your browser and start a private window after disconnecting the Encrypted VPN Internet Access. Thanks.</string>
-    <string name="yes">Yes</string>
-    <string name="no">No</string>
     <string name="eip_state_not_connected">"Not running! Connection not secure!"</string>
     <string name="eip_state_connected">Connection Secure.</string>
     <string name="provider_problem">It seems there is a problem with the provider.</string>
     <string name="try_another_provider">Please try another provider, or contact yours.</string>
-    <string name="default_user">You</string>
+    <string name="default_username">Anonymous</string>
     <string name="logged_in_user_status">is logged in.</string>
     <string name="logged_out_user_status">logged out.</string>
     <string name="didnt_log_out_user_status">didn\'t log out. Try later, it may be a problem in the network or in the provider. If the problem persists, then wipe Bitmask data from the Android settings</string>
@@ -77,4 +75,6 @@
     <string name="logging_in_user_status">is logging in.</string>
     <string name="logging_out_user_status">is logging out.</string>
     <string name="signingup_message">is being registered.</string>
+    <string name="vpn.button.turn.on">Turn on</string>
+    <string name="vpn.button.turn.off">Turn off</string>
 </resources>
diff --git a/app/src/release/java/se/leap/bitmaskclient/ConfigurationWizard.java b/app/src/release/java/se/leap/bitmaskclient/ConfigurationWizard.java
index 68ff9e471761617152cde9013d562dc24462be49..61c6b7cf3bc3be7088f0cc7b4f79cb8ec4b9e07c 100644
--- a/app/src/release/java/se/leap/bitmaskclient/ConfigurationWizard.java
+++ b/app/src/release/java/se/leap/bitmaskclient/ConfigurationWizard.java
@@ -39,6 +39,7 @@ import se.leap.bitmaskclient.NewProviderDialog.NewProviderDialogInterface;
 import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver;
 import se.leap.bitmaskclient.ProviderDetailFragment.ProviderDetailFragmentInterface;
 import se.leap.bitmaskclient.eip.Constants;
+import se.leap.bitmaskclient.userstatus.SessionDialog;
 
 /**
  * Activity that builds and shows the list of known available providers.
@@ -98,8 +99,7 @@ public class ConfigurationWizard extends Activity
             outState.putInt(PROGRESSBAR_NUMBER, mProgressBar.getProgress());
         if (progressbar_description != null)
             outState.putString(PROGRESSBAR_TEXT, progressbar_description.getText().toString());
-        if (selected_provider != null)
-            outState.putParcelable(Provider.KEY, selected_provider);
+        outState.putParcelable(Provider.KEY, selected_provider);
         super.onSaveInstanceState(outState);
     }
 
@@ -125,8 +125,7 @@ public class ConfigurationWizard extends Activity
         selected_provider = savedInstanceState.getParcelable(Provider.KEY);
 
         if (fragment_manager.findFragmentByTag(ProviderDetailFragment.TAG) == null && setting_up_provider) {
-            if (selected_provider != null)
-                onItemSelectedUi();
+            onItemSelectedUi();
             if (progress > 0)
                 mProgressBar.setProgress(progress);
         }
@@ -166,8 +165,7 @@ public class ConfigurationWizard extends Activity
     }
 
     private void setUpProviderAPIResultReceiver() {
-        providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler());
-        providerAPI_result_receiver.setReceiver(this);
+        providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler(), this);
         providerAPI_broadcast_receiver_update = new ProviderAPIBroadcastReceiver_Update();
 
         IntentFilter update_intent_filter = new IntentFilter(ProviderAPI.UPDATE_PROGRESSBAR);
@@ -195,8 +193,6 @@ public class ConfigurationWizard extends Activity
                 mProgressBar.incrementProgressBy(1);
                 hideProgressBar();
 
-                setResult(RESULT_OK);
-
                 showProviderDetails();
             }
         } else if (resultCode == ProviderAPI.PROVIDER_NOK) {
@@ -213,8 +209,6 @@ public class ConfigurationWizard extends Activity
             hideProgressBar();
 
             showProviderDetails();
-
-            setResult(RESULT_OK);
         } else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) {
             hideProgressBar();
 
diff --git a/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java
index a96556bc532d9fdddfcbe94d43d713cea10dcb91..a3f7db6aef07e14c026c7d3019c7d7080fc34114 100644
--- a/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java
+++ b/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java
@@ -36,8 +36,10 @@ import org.apache.http.client.*;
 import org.json.*;
 import org.thoughtcrime.ssl.pinning.util.*;
 
-import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
 import se.leap.bitmaskclient.eip.*;
+import se.leap.bitmaskclient.userstatus.SessionDialog;
+import se.leap.bitmaskclient.userstatus.User;
+import se.leap.bitmaskclient.userstatus.UserStatus;
 
 /**
  * Implements HTTP api methods used to manage communications with the provider server.
@@ -141,7 +143,7 @@ public class ProviderAPI extends IntentService {
                 }
             }
         } else if (action.equalsIgnoreCase(SIGN_UP)) {
-            UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.SIGNING_UP, resources);
+            UserStatus.updateStatus(UserStatus.SessionStatus.SIGNING_UP, resources);
             Bundle result = tryToRegister(parameters);
             if (result.getBoolean(RESULT_KEY)) {
                 receiver.send(SUCCESSFUL_SIGNUP, result);
@@ -149,23 +151,23 @@ public class ProviderAPI extends IntentService {
                 receiver.send(FAILED_SIGNUP, result);
             }
         } else if (action.equalsIgnoreCase(LOG_IN)) {
-            UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGING_IN, resources);
+            UserStatus.updateStatus(UserStatus.SessionStatus.LOGGING_IN, resources);
             Bundle result = tryToAuthenticate(parameters);
             if (result.getBoolean(RESULT_KEY)) {
                 receiver.send(SUCCESSFUL_LOGIN, result);
-                UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGED_IN, resources);
+                UserStatus.updateStatus(UserStatus.SessionStatus.LOGGED_IN, resources);
             } else {
                 receiver.send(FAILED_LOGIN, result);
-                UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.NOT_LOGGED_IN, resources);
+                UserStatus.updateStatus(UserStatus.SessionStatus.NOT_LOGGED_IN, resources);
             }
         } else if (action.equalsIgnoreCase(LOG_OUT)) {
-            UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGING_OUT, resources);
+            UserStatus.updateStatus(UserStatus.SessionStatus.LOGGING_OUT, resources);
             if (logOut()) {
                 receiver.send(SUCCESSFUL_LOGOUT, Bundle.EMPTY);
-                UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGED_OUT, resources);
+                UserStatus.updateStatus(UserStatus.SessionStatus.LOGGED_OUT, resources);
             } else {
                 receiver.send(LOGOUT_FAILED, Bundle.EMPTY);
-                UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.DIDNT_LOG_OUT, resources);
+                UserStatus.updateStatus(UserStatus.SessionStatus.DIDNT_LOG_OUT, resources);
             }
         } else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) {
             if (updateVpnCertificate()) {
diff --git a/build.gradle b/build.gradle
index 0b8e4725ed2a865c963b5445856f1b9b5a504866..a27276d004c15020b010e1094ec8d150bb0087d8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,12 +1,10 @@
-import org.apache.tools.ant.filters.ReplaceTokens
-
 buildscript {
   repositories {
     mavenCentral()
     jcenter()
   }
   dependencies {
-    classpath 'com.android.tools.build:gradle:1.0.0'
+    classpath 'com.android.tools.build:gradle:1.2.3'
     classpath 'org.ajoberstar:gradle-git:0.10+'
   }
 }
@@ -14,5 +12,6 @@ buildscript {
 allprojects {
   repositories {
     mavenCentral()
+    jcenter()
   }
 }
\ No newline at end of file