diff --git a/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/DownloadBroadcastReceiver.java b/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/DownloadBroadcastReceiver.java
index a4acc2aa30d056da8a3dd114b0bada333d0aa78e..c3a4c890b4bb25239eabe4d83ac10012b454bc78 100644
--- a/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/DownloadBroadcastReceiver.java
+++ b/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/DownloadBroadcastReceiver.java
@@ -24,7 +24,7 @@ import android.widget.Toast;
 
 import se.leap.bitmaskclient.Constants;
 import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
 
 import static android.app.Activity.RESULT_CANCELED;
 import static se.leap.bitmaskclient.Constants.BROADCAST_DOWNLOAD_SERVICE_EVENT;
diff --git a/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/InstallActivity.java b/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/InstallActivity.java
index 6629425c6859ee7575e4abd49d27ef49588ba2f8..37a5f01e9560b29ccce5a44a5f4417f9947aea18 100644
--- a/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/InstallActivity.java
+++ b/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/InstallActivity.java
@@ -29,7 +29,7 @@ import androidx.annotation.Nullable;
 import java.io.File;
 
 import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
 
 import static se.leap.bitmaskclient.Constants.REQUEST_CODE_REQUEST_UPDATE;
 import static se.leap.bitmaskclient.appUpdate.DownloadConnector.APP_TYPE;
diff --git a/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/UpdateDownloadManager.java b/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/UpdateDownloadManager.java
index b79c2a911ac03b9e133b12d39e0f90a1582f599f..0db53297add8a6521d65273b7b357159bcd774b2 100644
--- a/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/UpdateDownloadManager.java
+++ b/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/UpdateDownloadManager.java
@@ -48,7 +48,7 @@ import static se.leap.bitmaskclient.appUpdate.DownloadService.UPDATE_NOT_FOUND;
 import static se.leap.bitmaskclient.appUpdate.DownloadService.VERIFICATION_ERROR;
 import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.CHECK_VERSION_FILE;
 import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.DOWNLOAD_UPDATE;
-import static se.leap.bitmaskclient.utils.FileHelper.readPublicKey;
+import static se.leap.bitmaskclient.base.utils.FileHelper.readPublicKey;
 
 public class UpdateDownloadManager implements Logger, DownloadConnector.DownloadProgress {
 
diff --git a/app/src/insecure/java/se/leap/bitmaskclient/AddProviderActivity.java b/app/src/insecure/java/se/leap/bitmaskclient/providersetup/AddProviderActivity.java
similarity index 92%
rename from app/src/insecure/java/se/leap/bitmaskclient/AddProviderActivity.java
rename to app/src/insecure/java/se/leap/bitmaskclient/providersetup/AddProviderActivity.java
index 102a72c319ce7b117ea5f4f13b05ada78d4f92a3..a566f37add01af1d0aa385e96499e48e8d18198a 100644
--- a/app/src/insecure/java/se/leap/bitmaskclient/AddProviderActivity.java
+++ b/app/src/insecure/java/se/leap/bitmaskclient/providersetup/AddProviderActivity.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import android.os.Bundle;
 import android.view.View;
@@ -9,10 +9,12 @@ import android.widget.RelativeLayout;
 
 import butterknife.InjectView;
 import butterknife.Optional;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.providersetup.activities.AddProviderBaseActivity;
 
 import static android.widget.RelativeLayout.BELOW;
 import static android.widget.RelativeLayout.LEFT_OF;
-import static se.leap.bitmaskclient.Constants.DANGER_ON;
+import static se.leap.bitmaskclient.base.models.Constants.DANGER_ON;
 
 public class AddProviderActivity extends AddProviderBaseActivity {
 
diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/insecure/java/se/leap/bitmaskclient/providersetup/ProviderApiManager.java
similarity index 95%
rename from app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java
rename to app/src/insecure/java/se/leap/bitmaskclient/providersetup/ProviderApiManager.java
index a111e907b8bea52e9ef13a212d9058e35df73323..a13f056fe62d4774d1e3490ff018587f9c8c1c0a 100644
--- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java
+++ b/app/src/insecure/java/se/leap/bitmaskclient/providersetup/ProviderApiManager.java
@@ -15,7 +15,7 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import android.content.SharedPreferences;
 import android.content.res.Resources;
@@ -45,17 +45,13 @@ import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 
 import okhttp3.OkHttpClient;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.utils.ConfigHelper;
 import se.leap.bitmaskclient.eip.EIP;
-import se.leap.bitmaskclient.utils.ConfigHelper;
+import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator;
 
 import static android.text.TextUtils.isEmpty;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
-import static se.leap.bitmaskclient.Constants.DANGER_ON;
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
-import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING;
-import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON;
 import static se.leap.bitmaskclient.R.string.certificate_error;
 import static se.leap.bitmaskclient.R.string.downloading_vpn_certificate_failed;
 import static se.leap.bitmaskclient.R.string.error_io_exception_user_message;
@@ -63,7 +59,14 @@ import static se.leap.bitmaskclient.R.string.malformed_url;
 import static se.leap.bitmaskclient.R.string.setup_error_text;
 import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_cert;
 import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_details;
-import static se.leap.bitmaskclient.utils.ConfigHelper.getProviderFormattedString;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.DANGER_ON;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON;
 
 /**
  * Created by cyberta on 04.01.18.
diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailActivity.java b/app/src/insecure/java/se/leap/bitmaskclient/providersetup/ProviderDetailActivity.java
similarity index 63%
rename from app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailActivity.java
rename to app/src/insecure/java/se/leap/bitmaskclient/providersetup/ProviderDetailActivity.java
index 9f2fa284bea29c73b2fb3e2d6ff6173c1e9f0a94..2b62a7decf3cbac68fe2c481d96c4ee564d38fb2 100644
--- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailActivity.java
+++ b/app/src/insecure/java/se/leap/bitmaskclient/providersetup/ProviderDetailActivity.java
@@ -1,7 +1,10 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import android.content.SharedPreferences;
 
+import se.leap.bitmaskclient.base.models.Constants;
+import se.leap.bitmaskclient.providersetup.activities.AbstractProviderDetailActivity;
+
 public class ProviderDetailActivity extends AbstractProviderDetailActivity {
 
     @Override
diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java b/app/src/insecure/java/se/leap/bitmaskclient/providersetup/ProviderListActivity.java
similarity index 83%
rename from app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java
rename to app/src/insecure/java/se/leap/bitmaskclient/providersetup/ProviderListActivity.java
index d151c987e853745046eba450ddb50532b457f310..46eb2a05f203e497845d33036f1fb2c2c1d2bf2f 100644
--- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java
+++ b/app/src/insecure/java/se/leap/bitmaskclient/providersetup/ProviderListActivity.java
@@ -14,14 +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.providersetup;
 
 import android.os.Bundle;
 import androidx.annotation.NonNull;
 
-import static se.leap.bitmaskclient.Constants.DANGER_ON;
-import static se.leap.bitmaskclient.ProviderAPI.SET_UP_PROVIDER;
-import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.activities.ProviderListBaseActivity;
+
+import static se.leap.bitmaskclient.base.models.Constants.DANGER_ON;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.SET_UP_PROVIDER;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER;
 
 /**
  * Activity that builds and shows the list of known available providers.
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ec05318586ed74a5d02d7d9781ce5999bce7d274..7e964211e7911b12c74375889abeea34432e6c13 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -29,7 +29,7 @@
 		     android:maxSdkVersion="18"/>
 
     <application
-        android:name=".BitmaskApp"
+        android:name=".base.BitmaskApp"
         android:allowBackup="true"
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_name"
@@ -50,13 +50,13 @@
             </intent-filter>
         </service>
         <service
-            android:name=".ProviderAPI"
+            android:name=".providersetup.ProviderAPI"
             android:exported="false"
             android:permission="android.permission.BIND_JOB_SERVICE">
         </service>
 
         <receiver
-            android:name=".OnBootReceiver"
+            android:name=".base.OnBootReceiver"
             android:enabled="true"
             android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
           <intent-filter android:priority="999">
@@ -71,7 +71,7 @@
             android:name="de.blinkt.openvpn.LaunchVPN"
             android:theme="@style/invisibleTheme" />
         <activity
-            android:name=".StartActivity"
+            android:name=".base.StartActivity"
             android:label="@string/app_name"
             android:launchMode="singleTop"
             android:theme="@style/SplashTheme"
@@ -87,29 +87,29 @@
         </activity>
 
         <activity
-            android:name=".MainActivity"
+            android:name=".base.MainActivity"
             android:label="@string/app_name"
             android:launchMode="singleTop" />
 
         <activity
-            android:name=".ProviderListActivity"
+            android:name=".providersetup.ProviderListActivity"
             android:label="@string/configuration_wizard_title" />
 
         <activity
-            android:name=".CustomProviderSetupActivity"
+            android:name=".providersetup.activities.CustomProviderSetupActivity"
             android:label="@string/setup_provider" />
 
         <activity
-            android:name=".AddProviderActivity"
+            android:name=".providersetup.AddProviderActivity"
             android:label="@string/add_provider" />
 
         <activity
-            android:name=".ProviderDetailActivity"
+            android:name=".providersetup.ProviderDetailActivity"
             android:label="@string/provider_details_title"
             android:launchMode="singleTop" />
 
-        <activity android:name=".LoginActivity" />
-        <activity android:name=".SignupActivity" />
+        <activity android:name=".providersetup.activities.LoginActivity" />
+        <activity android:name=".providersetup.activities.SignupActivity" />
 
         <service
             android:name=".eip.EIP"
@@ -118,7 +118,7 @@
         </service>
 
         <service
-            android:name=".BitmaskTileService"
+            android:name=".base.BitmaskTileService"
             android:icon="@drawable/vpn_disconnected"
             android:label="@string/qs_title"
             android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
diff --git a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
index 70f8e4453cf6561d197cc15e39e12bffa955ab00..b148d04dbc54b0fc0e5395d5dce7e489c3403929 100644
--- a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
+++ b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
@@ -23,11 +23,11 @@ import de.blinkt.openvpn.core.ConnectionStatus;
 import de.blinkt.openvpn.core.Preferences;
 import de.blinkt.openvpn.core.VPNLaunchHelper;
 import de.blinkt.openvpn.core.VpnStatus;
-import se.leap.bitmaskclient.MainActivity;
+import se.leap.bitmaskclient.base.MainActivity;
 import se.leap.bitmaskclient.R;
 
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_PREPARE_VPN;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_PREPARE_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE;
 import static se.leap.bitmaskclient.eip.EipResultBroadcast.tellToReceiverOrBroadcast;
 
 /**
diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
index 519c2106fd96df920ef9c82aeb0e3e58ecf32222..5df1d56b1b8636a7c9c571610e165e349abfc686 100644
--- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
+++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
@@ -69,8 +69,8 @@ import se.leap.bitmaskclient.BuildConfig;
 import se.leap.bitmaskclient.R;
 
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE;
-import static se.leap.bitmaskclient.utils.ConfigHelper.stringEqual;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.stringEqual;
 
 public class VpnProfile implements Serializable, Cloneable {
     // Note that this class cannot be moved to core where it belongs since
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
index 619697697af99e4d02cf50fdfa7c54e3b55ff1bb..7dfacd91368ddf36b88585bc056b0d7144f7f2c9 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
@@ -45,14 +45,14 @@ import de.blinkt.openvpn.core.VpnStatus.StateListener;
 import de.blinkt.openvpn.core.connection.Connection;
 import de.blinkt.openvpn.core.connection.Obfs4Connection;
 import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.VpnNotificationManager;
+import se.leap.bitmaskclient.eip.VpnNotificationManager;
 import se.leap.bitmaskclient.pluggableTransports.Shapeshifter;
 import se.leap.bitmaskclient.firewall.FirewallManager;
 
 import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED;
 import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT;
 import static de.blinkt.openvpn.core.NetworkSpace.IpAddress;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE;
 
 
 public class OpenVPNService extends VpnService implements StateListener, Callback, ByteCountListener, IOpenVPNServiceInternal, VpnNotificationManager.VpnServiceCallback {
diff --git a/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java b/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
index 737b8b4232355efda3083d7bd8fa6defaba48099..8007f7c5458630ea7a763650079ee30d02ddea17 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
@@ -21,9 +21,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import de.blinkt.openvpn.VpnProfile;
 import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
 
-import static se.leap.bitmaskclient.utils.ConfigHelper.getProviderFormattedString;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString;
 
 public class VpnStatus {
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/DrawerSettingsAdapter.java b/app/src/main/java/se/leap/bitmaskclient/DrawerSettingsAdapter.java
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/app/src/main/java/se/leap/bitmaskclient/BitmaskApp.java b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java
similarity index 87%
rename from app/src/main/java/se/leap/bitmaskclient/BitmaskApp.java
rename to app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java
index 437998e0c0f753bd971f2e210728063d9e9678c2..4b6fea723409bd1460c6c9123e08562d6545e9b1 100644
--- a/app/src/main/java/se/leap/bitmaskclient/BitmaskApp.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java
@@ -15,7 +15,7 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.base;
 
 import android.content.Context;
 import android.content.IntentFilter;
@@ -28,16 +28,20 @@ import androidx.multidex.MultiDexApplication;
 import com.squareup.leakcanary.LeakCanary;
 import com.squareup.leakcanary.RefWatcher;
 
+import se.leap.bitmaskclient.BuildConfig;
 import se.leap.bitmaskclient.appUpdate.DownloadBroadcastReceiver;
+import se.leap.bitmaskclient.eip.EipSetupObserver;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
 import se.leap.bitmaskclient.tethering.TetheringStateManager;
+import se.leap.bitmaskclient.base.utils.PRNGFixes;
 
 import static android.content.Intent.CATEGORY_DEFAULT;
-import static se.leap.bitmaskclient.Constants.BROADCAST_DOWNLOAD_SERVICE_EVENT;
-import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_DOWNLOAD_SERVICE_EVENT;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
 import static se.leap.bitmaskclient.appUpdate.DownloadBroadcastReceiver.ACTION_DOWNLOAD;
 import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.CHECK_VERSION_FILE;
 import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.DOWNLOAD_UPDATE;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.getSavedProviderFromSharedPreferences;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getSavedProviderFromSharedPreferences;
 
 /**
  * Created by cyberta on 24.10.17.
diff --git a/app/src/main/java/se/leap/bitmaskclient/BitmaskTileService.java b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskTileService.java
similarity index 94%
rename from app/src/main/java/se/leap/bitmaskclient/BitmaskTileService.java
rename to app/src/main/java/se/leap/bitmaskclient/base/BitmaskTileService.java
index 4b4236242c921aae7512d5eeb76dd2844b32548a..4a8b123631ec6cac4927e8401e1dab5d467a7bff 100644
--- a/app/src/main/java/se/leap/bitmaskclient/BitmaskTileService.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskTileService.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.base;
 
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
@@ -11,8 +11,11 @@ import android.service.quicksettings.TileService;
 import java.util.Observable;
 import java.util.Observer;
 
+import se.leap.bitmaskclient.R;
 import se.leap.bitmaskclient.eip.EipCommand;
 import se.leap.bitmaskclient.eip.EipStatus;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
 
 
 @TargetApi(Build.VERSION_CODES.N)
diff --git a/app/src/main/java/se/leap/bitmaskclient/FragmentManagerEnhanced.java b/app/src/main/java/se/leap/bitmaskclient/base/FragmentManagerEnhanced.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/FragmentManagerEnhanced.java
rename to app/src/main/java/se/leap/bitmaskclient/base/FragmentManagerEnhanced.java
index f4215e897654e22ebeff02deea0de5754678b08a..bc01dcec99962cb870320f31abc0b4c9646daf12 100644
--- a/app/src/main/java/se/leap/bitmaskclient/FragmentManagerEnhanced.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/FragmentManagerEnhanced.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.base;
 
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
diff --git a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java
similarity index 85%
rename from app/src/main/java/se/leap/bitmaskclient/MainActivity.java
rename to app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java
index 867f66e5b4d047dda85d721de0f9a38215d1776f..1b7de10e4eca3ff2cd597a83973278aced136d2a 100644
--- a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.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.base;
 
 
 import android.content.Intent;
@@ -34,34 +34,43 @@ import org.json.JSONObject;
 import java.util.Observable;
 import java.util.Observer;
 
-import se.leap.bitmaskclient.drawer.NavigationDrawerFragment;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.base.drawer.NavigationDrawerFragment;
 import se.leap.bitmaskclient.eip.EIP;
 import se.leap.bitmaskclient.eip.EipCommand;
-import se.leap.bitmaskclient.fragments.ExcludeAppsFragment;
-import se.leap.bitmaskclient.fragments.LogFragment;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
-
-import static se.leap.bitmaskclient.Constants.ASK_TO_CANCEL_VPN;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_PREPARE_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;
-import static se.leap.bitmaskclient.Constants.EIP_REQUEST;
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_LOG_IN;
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_SWITCH_PROVIDER;
-import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
-import static se.leap.bitmaskclient.ProviderAPI.ERRORID;
-import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
-import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE;
-import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.USER_MESSAGE;
+import se.leap.bitmaskclient.eip.EipSetupListener;
+import se.leap.bitmaskclient.eip.EipSetupObserver;
+import se.leap.bitmaskclient.base.fragments.EipFragment;
+import se.leap.bitmaskclient.base.fragments.ExcludeAppsFragment;
+import se.leap.bitmaskclient.base.fragments.LogFragment;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
+import se.leap.bitmaskclient.providersetup.models.LeapSRPSession;
+import se.leap.bitmaskclient.providersetup.activities.LoginActivity;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.fragments.MainActivityErrorDialog;
+
+import static se.leap.bitmaskclient.base.models.Constants.ASK_TO_CANCEL_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_PREPARE_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_REQUEST;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP;
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_LOG_IN;
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORID;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE;
 import static se.leap.bitmaskclient.R.string.downloading_vpn_certificate_failed;
 import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message;
 import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_VPN_CERTIFICATE;
 import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_VPN_PREPARE;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.storeProviderInPreferences;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.storeProviderInPreferences;
 
 
 public class MainActivity extends AppCompatActivity implements EipSetupListener, Observer, ExcludeAppsFragment.ExcludedAppsCallback {
diff --git a/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java b/app/src/main/java/se/leap/bitmaskclient/base/OnBootReceiver.java
similarity index 83%
rename from app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
rename to app/src/main/java/se/leap/bitmaskclient/base/OnBootReceiver.java
index 2efce9e45357062f2a404dc7f64832fecbf076fd..df1d3e5a3e3d664151b2847daa1c09413b062b92 100644
--- a/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/OnBootReceiver.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.base;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -7,14 +7,12 @@ import android.content.SharedPreferences;
 import android.util.Log;
 
 import de.blinkt.openvpn.core.VpnStatus;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
 
 import static android.content.Intent.ACTION_BOOT_COMPLETED;
-import static se.leap.bitmaskclient.Constants.APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE;
-import static se.leap.bitmaskclient.Constants.EIP_IS_ALWAYS_ON;
-import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT;
-import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.base.models.Constants.APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
 
 public class OnBootReceiver extends BroadcastReceiver {
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/StartActivity.java b/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java
similarity index 86%
rename from app/src/main/java/se/leap/bitmaskclient/StartActivity.java
rename to app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java
index 1a679b1cb6aeff12035dd52ddbab77327e8f3d02..cf64905a442cb05b5784c33e787e4cd2bdebb242 100644
--- a/app/src/main/java/se/leap/bitmaskclient/StartActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.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.base;
 
 import android.app.Activity;
 import android.content.Intent;
@@ -30,19 +30,24 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 import de.blinkt.openvpn.core.VpnStatus;
+import se.leap.bitmaskclient.providersetup.ProviderListActivity;
 import se.leap.bitmaskclient.eip.EipCommand;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
-
-import static se.leap.bitmaskclient.Constants.APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE;
-import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT;
-import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION;
-import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION;
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
-import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
-import static se.leap.bitmaskclient.MainActivity.ACTION_SHOW_VPN_FRAGMENT;
-import static se.leap.bitmaskclient.utils.ConfigHelper.isDefaultBitmask;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.storeProviderInPreferences;
+import se.leap.bitmaskclient.base.models.FeatureVersionCode;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
+import se.leap.bitmaskclient.providersetup.activities.CustomProviderSetupActivity;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
+
+import static se.leap.bitmaskclient.base.models.Constants.APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT;
+import static se.leap.bitmaskclient.base.models.Constants.PREFERENCES_APP_VERSION;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_EIP_DEFINITION;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.storeProviderInPreferences;
 
 /**
  * Activity shown at startup. Evaluates if App is started for the first time or has been upgraded
diff --git a/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/drawer/NavigationDrawerFragment.java
similarity index 92%
rename from app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java
rename to app/src/main/java/se/leap/bitmaskclient/base/drawer/NavigationDrawerFragment.java
index fabaa7c3f278c77aca6c1d3e4287a8694685ed47..e70c87f95de0caa4889912d3fe02669e08e4dca7 100644
--- a/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/drawer/NavigationDrawerFragment.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.drawer;
+package se.leap.bitmaskclient.base.drawer;
 
 
 import android.app.Activity;
@@ -50,47 +50,47 @@ import java.util.Observer;
 import java.util.Set;
 
 import de.blinkt.openvpn.core.VpnStatus;
-import se.leap.bitmaskclient.EipFragment;
-import se.leap.bitmaskclient.FragmentManagerEnhanced;
-import se.leap.bitmaskclient.MainActivity;
-import se.leap.bitmaskclient.Provider;
-import se.leap.bitmaskclient.ProviderListActivity;
-import se.leap.bitmaskclient.ProviderObservable;
+import se.leap.bitmaskclient.base.fragments.EipFragment;
+import se.leap.bitmaskclient.base.FragmentManagerEnhanced;
+import se.leap.bitmaskclient.base.MainActivity;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.ProviderListActivity;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
 import se.leap.bitmaskclient.R;
 import se.leap.bitmaskclient.eip.EipCommand;
 import se.leap.bitmaskclient.eip.EipStatus;
 import se.leap.bitmaskclient.firewall.FirewallManager;
-import se.leap.bitmaskclient.fragments.AboutFragment;
-import se.leap.bitmaskclient.fragments.AlwaysOnDialog;
-import se.leap.bitmaskclient.fragments.ExcludeAppsFragment;
-import se.leap.bitmaskclient.fragments.LogFragment;
-import se.leap.bitmaskclient.fragments.TetheringDialog;
+import se.leap.bitmaskclient.base.fragments.AboutFragment;
+import se.leap.bitmaskclient.base.fragments.AlwaysOnDialog;
+import se.leap.bitmaskclient.base.fragments.ExcludeAppsFragment;
+import se.leap.bitmaskclient.base.fragments.LogFragment;
+import se.leap.bitmaskclient.base.fragments.TetheringDialog;
 import se.leap.bitmaskclient.tethering.TetheringObservable;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
-import se.leap.bitmaskclient.views.IconSwitchEntry;
-import se.leap.bitmaskclient.views.IconTextEntry;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.views.IconSwitchEntry;
+import se.leap.bitmaskclient.base.views.IconTextEntry;
 
 import static android.content.Context.MODE_PRIVATE;
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
-import static se.leap.bitmaskclient.BitmaskApp.getRefWatcher;
-import static se.leap.bitmaskclient.Constants.DONATION_URL;
-import static se.leap.bitmaskclient.Constants.ENABLE_DONATION;
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_SWITCH_PROVIDER;
-import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
-import static se.leap.bitmaskclient.Constants.USE_IPv6_FIREWALL;
-import static se.leap.bitmaskclient.Constants.USE_PLUGGABLE_TRANSPORTS;
+import static se.leap.bitmaskclient.base.BitmaskApp.getRefWatcher;
+import static se.leap.bitmaskclient.base.models.Constants.DONATION_URL;
+import static se.leap.bitmaskclient.base.models.Constants.ENABLE_DONATION;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL;
+import static se.leap.bitmaskclient.base.models.Constants.USE_PLUGGABLE_TRANSPORTS;
 import static se.leap.bitmaskclient.R.string.about_fragment_title;
 import static se.leap.bitmaskclient.R.string.exclude_apps_fragment_title;
 import static se.leap.bitmaskclient.R.string.log_fragment_title;
-import static se.leap.bitmaskclient.utils.ConfigHelper.isDefaultBitmask;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.getSaveBattery;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.getShowAlwaysOnDialog;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.getUsePluggableTransports;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.saveBattery;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.showExperimentalFeatures;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.usePluggableTransports;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getSaveBattery;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getShowAlwaysOnDialog;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePluggableTransports;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.saveBattery;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.showExperimentalFeatures;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.usePluggableTransports;
 
 /**
  * Fragment used for managing interactions for and presentation of a navigation drawer.
diff --git a/app/src/main/java/se/leap/bitmaskclient/fragments/AboutFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java
similarity index 97%
rename from app/src/main/java/se/leap/bitmaskclient/fragments/AboutFragment.java
rename to app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java
index b7743a755793951da22a5296b85af84199d7e05a..d901ba68b82d10f96c45cb47b7727329ae50d9f7 100644
--- a/app/src/main/java/se/leap/bitmaskclient/fragments/AboutFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.fragments;
+package se.leap.bitmaskclient.base.fragments;
 
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
diff --git a/app/src/main/java/se/leap/bitmaskclient/fragments/AlwaysOnDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/AlwaysOnDialog.java
similarity index 92%
rename from app/src/main/java/se/leap/bitmaskclient/fragments/AlwaysOnDialog.java
rename to app/src/main/java/se/leap/bitmaskclient/base/fragments/AlwaysOnDialog.java
index cb26e6853d0f3a44fed26c17473afb427707cd5b..a8034e1a14d4fea5f0e89b48e0b08cc8c0b97f86 100644
--- a/app/src/main/java/se/leap/bitmaskclient/fragments/AlwaysOnDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/AlwaysOnDialog.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.fragments;
+package se.leap.bitmaskclient.base.fragments;
 
 import android.app.Dialog;
 import android.content.Intent;
@@ -16,9 +16,9 @@ import android.widget.CheckBox;
 import butterknife.ButterKnife;
 import butterknife.InjectView;
 import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.views.IconTextView;
+import se.leap.bitmaskclient.base.views.IconTextView;
 
-import static se.leap.bitmaskclient.utils.PreferenceHelper.saveShowAlwaysOnDialog;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.saveShowAlwaysOnDialog;
 
 
 /**
diff --git a/app/src/main/java/se/leap/bitmaskclient/fragments/DonationReminderDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/DonationReminderDialog.java
similarity index 84%
rename from app/src/main/java/se/leap/bitmaskclient/fragments/DonationReminderDialog.java
rename to app/src/main/java/se/leap/bitmaskclient/base/fragments/DonationReminderDialog.java
index 046acad47d07844b776d3f924dcb5185143d6d19..0277933c65d15f3090f779d4f5e710bbdfd90445 100644
--- a/app/src/main/java/se/leap/bitmaskclient/fragments/DonationReminderDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/DonationReminderDialog.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.fragments;
+package se.leap.bitmaskclient.base.fragments;
 
 import android.app.Dialog;
 import android.content.ActivityNotFoundException;
@@ -20,15 +20,15 @@ import java.text.ParseException;
 import butterknife.ButterKnife;
 import butterknife.InjectView;
 import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.utils.DateHelper;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
-
-import static se.leap.bitmaskclient.Constants.DONATION_REMINDER_DURATION;
-import static se.leap.bitmaskclient.Constants.DONATION_URL;
-import static se.leap.bitmaskclient.Constants.ENABLE_DONATION;
-import static se.leap.bitmaskclient.Constants.ENABLE_DONATION_REMINDER;
-import static se.leap.bitmaskclient.Constants.FIRST_TIME_USER_DATE;
-import static se.leap.bitmaskclient.Constants.LAST_DONATION_REMINDER_DATE;
+import se.leap.bitmaskclient.base.utils.DateHelper;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
+
+import static se.leap.bitmaskclient.base.models.Constants.DONATION_REMINDER_DURATION;
+import static se.leap.bitmaskclient.base.models.Constants.DONATION_URL;
+import static se.leap.bitmaskclient.base.models.Constants.ENABLE_DONATION;
+import static se.leap.bitmaskclient.base.models.Constants.ENABLE_DONATION_REMINDER;
+import static se.leap.bitmaskclient.base.models.Constants.FIRST_TIME_USER_DATE;
+import static se.leap.bitmaskclient.base.models.Constants.LAST_DONATION_REMINDER_DATE;
 
 public class DonationReminderDialog extends AppCompatDialogFragment {
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java
similarity index 91%
rename from app/src/main/java/se/leap/bitmaskclient/EipFragment.java
rename to app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java
index fceadd8834474e37b6566f19406bdd05ffcd98b8..9544fb1e2bfad2a890d2ddf165422ebae8b20c81 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.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.base.fragments;
 
 import android.app.Activity;
 import android.content.ComponentName;
@@ -54,32 +54,40 @@ import butterknife.OnClick;
 import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
 import de.blinkt.openvpn.core.OpenVPNService;
 import de.blinkt.openvpn.core.VpnStatus;
+import se.leap.bitmaskclient.providersetup.ProviderListActivity;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.base.FragmentManagerEnhanced;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
+import se.leap.bitmaskclient.base.views.VpnStateImage;
 import se.leap.bitmaskclient.eip.EipCommand;
 import se.leap.bitmaskclient.eip.EipStatus;
-import se.leap.bitmaskclient.fragments.DonationReminderDialog;
-import se.leap.bitmaskclient.views.VpnStateImage;
+import se.leap.bitmaskclient.providersetup.ProviderAPICommand;
+import se.leap.bitmaskclient.providersetup.activities.CustomProviderSetupActivity;
+import se.leap.bitmaskclient.providersetup.activities.LoginActivity;
+import se.leap.bitmaskclient.providersetup.models.LeapSRPSession;
 
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
 import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK;
-import static se.leap.bitmaskclient.Constants.ASK_TO_CANCEL_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;
-import static se.leap.bitmaskclient.Constants.EIP_EARLY_ROUTES;
-import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT;
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_LOG_IN;
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_SWITCH_PROVIDER;
-import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
-import static se.leap.bitmaskclient.EipSetupObserver.connectionRetry;
-import static se.leap.bitmaskclient.EipSetupObserver.gatewayOrder;
-import static se.leap.bitmaskclient.EipSetupObserver.reconnectingWithDifferentGateway;
-import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_GEOIP_JSON;
-import static se.leap.bitmaskclient.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.USER_MESSAGE;
 import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message;
-import static se.leap.bitmaskclient.utils.ConfigHelper.isDefaultBitmask;
-import static se.leap.bitmaskclient.utils.ViewHelper.convertDimensionToPx;
+import static se.leap.bitmaskclient.base.models.Constants.ASK_TO_CANCEL_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_EARLY_ROUTES;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP;
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_LOG_IN;
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask;
+import static se.leap.bitmaskclient.base.utils.ViewHelper.convertDimensionToPx;
+import static se.leap.bitmaskclient.eip.EipSetupObserver.connectionRetry;
+import static se.leap.bitmaskclient.eip.EipSetupObserver.gatewayOrder;
+import static se.leap.bitmaskclient.eip.EipSetupObserver.reconnectingWithDifferentGateway;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_GEOIP_JSON;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE;
 
 public class EipFragment extends Fragment implements Observer {
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/fragments/ExcludeAppsFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java
similarity index 99%
rename from app/src/main/java/se/leap/bitmaskclient/fragments/ExcludeAppsFragment.java
rename to app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java
index 9559978be0656a71717a6084e2d8ced30c13e86a..18000171cf639faa88d3ebec9882a5992570caef 100644
--- a/app/src/main/java/se/leap/bitmaskclient/fragments/ExcludeAppsFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java
@@ -3,7 +3,7 @@
  * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
  */
 
-package se.leap.bitmaskclient.fragments;
+package se.leap.bitmaskclient.base.fragments;
 
 import android.Manifest;
 import android.app.Activity;
@@ -37,7 +37,7 @@ import java.util.Vector;
 
 import de.blinkt.openvpn.VpnProfile;
 import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
 
 /**
  * Created by arne on 16.11.14.
diff --git a/app/src/main/java/se/leap/bitmaskclient/fragments/LogFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java
similarity index 99%
rename from app/src/main/java/se/leap/bitmaskclient/fragments/LogFragment.java
rename to app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java
index 19787dc3fddc461f51b2c81fe485d876cd4fcad8..d788b9e648ba484ca963d23a2a889751a9e49182 100644
--- a/app/src/main/java/se/leap/bitmaskclient/fragments/LogFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java
@@ -3,7 +3,7 @@
  * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
  */
 
-package se.leap.bitmaskclient.fragments;
+package se.leap.bitmaskclient.base.fragments;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -55,7 +55,7 @@ import de.blinkt.openvpn.core.Preferences;
 import de.blinkt.openvpn.core.VpnStatus;
 import de.blinkt.openvpn.core.VpnStatus.LogListener;
 import de.blinkt.openvpn.core.VpnStatus.StateListener;
-import se.leap.bitmaskclient.Constants;
+import se.leap.bitmaskclient.base.models.Constants;
 import se.leap.bitmaskclient.R;
 
 import static de.blinkt.openvpn.core.OpenVPNService.humanReadableByteCount;
diff --git a/app/src/main/java/se/leap/bitmaskclient/MainActivityErrorDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java
similarity index 93%
rename from app/src/main/java/se/leap/bitmaskclient/MainActivityErrorDialog.java
rename to app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java
index 7e9bad225879d1f4313584400842e209055d0ba8..4b307f2362ef3dd2b1ac631d153b21c284dd1ca1 100644
--- a/app/src/main/java/se/leap/bitmaskclient/MainActivityErrorDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.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.base.fragments;
 
 import android.app.Dialog;
 import android.content.Context;
@@ -26,18 +26,21 @@ import androidx.appcompat.app.AlertDialog;
 
 import org.json.JSONObject;
 
+import se.leap.bitmaskclient.R;
 import se.leap.bitmaskclient.eip.EIP;
 import se.leap.bitmaskclient.eip.EipCommand;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.ProviderAPICommand;
 
-import static se.leap.bitmaskclient.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE;
 import static se.leap.bitmaskclient.R.string.warning_option_try_ovpn;
 import static se.leap.bitmaskclient.R.string.warning_option_try_pt;
 import static se.leap.bitmaskclient.eip.EIP.EIPErrors.UNKNOWN;
 import static se.leap.bitmaskclient.eip.EIP.EIPErrors.valueOf;
 import static se.leap.bitmaskclient.eip.EIP.ERRORS;
 import static se.leap.bitmaskclient.eip.EIP.ERRORID;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.getUsePluggableTransports;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.usePluggableTransports;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePluggableTransports;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.usePluggableTransports;
 
 /**
  * Implements an error dialog for the main activity.
diff --git a/app/src/main/java/se/leap/bitmaskclient/fragments/TetheringDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/TetheringDialog.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/fragments/TetheringDialog.java
rename to app/src/main/java/se/leap/bitmaskclient/base/fragments/TetheringDialog.java
index 24e3c81400b62a211ac42d1b111d4f277c3c9b47..8593e25c0825f1c64819878c93461cd2ad4847b6 100644
--- a/app/src/main/java/se/leap/bitmaskclient/fragments/TetheringDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/TetheringDialog.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.fragments;
+package se.leap.bitmaskclient.base.fragments;
 
 import android.app.Dialog;
 import android.content.ActivityNotFoundException;
@@ -33,8 +33,8 @@ import de.blinkt.openvpn.core.VpnStatus;
 import se.leap.bitmaskclient.R;
 import se.leap.bitmaskclient.firewall.FirewallManager;
 import se.leap.bitmaskclient.tethering.TetheringObservable;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
-import se.leap.bitmaskclient.views.IconCheckboxEntry;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.views.IconCheckboxEntry;
 
 /**
  * Copyright (c) 2020 LEAP Encryption Access Project and contributers
diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/Constants.java
rename to app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
index 1d364074c5e0d72d8c235954bd6bb1419df550a7..d649aaf58b5ec2f1fe70654d876f60af080e0169 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Constants.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
@@ -14,10 +14,12 @@
  * 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.base.models;
 
 import android.text.TextUtils;
 
+import se.leap.bitmaskclient.BuildConfig;
+
 public interface Constants {
 
     //////////////////////////////////////////////
diff --git a/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java b/app/src/main/java/se/leap/bitmaskclient/base/models/DefaultedURL.java
similarity index 95%
rename from app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java
rename to app/src/main/java/se/leap/bitmaskclient/base/models/DefaultedURL.java
index 0cbb0d7200b1ab267e54af3d12f6c9ba033d44aa..4bb7e4eec67d51765f8f7bf0ece251c1b4497a1d 100644
--- a/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/DefaultedURL.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.base.models;
 
 import java.net.MalformedURLException;
 import java.net.URL;
diff --git a/app/src/main/java/se/leap/bitmaskclient/FeatureVersionCode.java b/app/src/main/java/se/leap/bitmaskclient/base/models/FeatureVersionCode.java
similarity index 72%
rename from app/src/main/java/se/leap/bitmaskclient/FeatureVersionCode.java
rename to app/src/main/java/se/leap/bitmaskclient/base/models/FeatureVersionCode.java
index 519e4fc21c1e60c65ed33c373eae457eb59dfb3a..7b3f1888b907b1caf7aafebe9ecec3398a71781b 100644
--- a/app/src/main/java/se/leap/bitmaskclient/FeatureVersionCode.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/FeatureVersionCode.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.base.models;
 
 public interface FeatureVersionCode {
     int RENAMED_EIP_IN_PREFERENCES = 132;
diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java
similarity index 96%
rename from app/src/main/java/se/leap/bitmaskclient/Provider.java
rename to app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java
index ce428a54c8906300cede76c7a806981bdf7a99f2..97f1019be7db583506e97ec75b71ab1dd8bfbca4 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Provider.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.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.base.models;
 
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -30,13 +30,13 @@ import java.net.URL;
 import java.util.Locale;
 
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
-import static se.leap.bitmaskclient.Constants.CAPABILITIES;
-import static se.leap.bitmaskclient.Constants.GATEWAYS;
-import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOWED_REGISTERED;
-import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOW_ANONYMOUS;
-import static se.leap.bitmaskclient.Constants.TRANSPORT;
-import static se.leap.bitmaskclient.Constants.TYPE;
-import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
+import static se.leap.bitmaskclient.base.models.Constants.CAPABILITIES;
+import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_ALLOWED_REGISTERED;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_ALLOW_ANONYMOUS;
+import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT;
+import static se.leap.bitmaskclient.base.models.Constants.TYPE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS;
 
 /**
  * @author Sean Leonard <meanderingcode@aetherislands.net>
@@ -259,7 +259,7 @@ public final class Provider implements Parcelable {
         }
     }
 
-    protected String getApiUrlWithVersion() {
+    public String getApiUrlWithVersion() {
         return getApiUrlString() + "/" + getApiVersion();
     }
 
@@ -272,7 +272,7 @@ public final class Provider implements Parcelable {
         return apiVersion;
     }
 
-    boolean hasCaCert() {
+    public boolean hasCaCert() {
         return caCert != null && !caCert.isEmpty();
     }
 
@@ -311,7 +311,7 @@ public final class Provider implements Parcelable {
         return name;
     }
 
-    protected String getDescription() {
+    public String getDescription() {
         String lang = Locale.getDefault().getLanguage();
         String desc = null;
         try {
@@ -328,7 +328,7 @@ public final class Provider implements Parcelable {
         return desc;
     }
 
-    protected boolean hasEIP() {
+    public boolean hasEIP() {
         return getEipServiceJson() != null && getEipServiceJson().length() > 0
                 && !getEipServiceJson().has(ERRORS);
     }
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderObservable.java b/app/src/main/java/se/leap/bitmaskclient/base/models/ProviderObservable.java
similarity index 95%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderObservable.java
rename to app/src/main/java/se/leap/bitmaskclient/base/models/ProviderObservable.java
index 50cc37d4f4b53d4b0de2caf946aef60b66caf5dd..19555504d0af464bd5160a64cdf24ad6af98200d 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderObservable.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/ProviderObservable.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.base.models;
 
 import java.util.Observable;
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/Cmd.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/Cmd.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/utils/Cmd.java
rename to app/src/main/java/se/leap/bitmaskclient/base/utils/Cmd.java
index 7b97add2d82c59d4cf5a5fe81759d5697f58eaf0..affceacf0f015ea0bd06fda4a2a3cc653373ff53 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/Cmd.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/Cmd.java
@@ -15,7 +15,7 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package se.leap.bitmaskclient.utils;
+package se.leap.bitmaskclient.base.utils;
 
 import androidx.annotation.WorkerThread;
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/utils/ConfigHelper.java
rename to app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java
index 5a142d9043e7fd919b8a1bfd3c4e1a512d56b594..4248072a9ccb2718efe1eb90e561fd94bf76191c 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/ConfigHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.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.utils;
+package se.leap.bitmaskclient.base.utils;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -46,10 +46,10 @@ import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.Calendar;
 
 import se.leap.bitmaskclient.BuildConfig;
-import se.leap.bitmaskclient.ProviderAPI;
+import se.leap.bitmaskclient.providersetup.ProviderAPI;
 import se.leap.bitmaskclient.R;
 
-import static se.leap.bitmaskclient.Constants.DEFAULT_BITMASK;
+import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_BITMASK;
 
 /**
  * Stores constants, and implements auxiliary methods used across all Bitmask Android classes.
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/DateHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/DateHelper.java
similarity index 95%
rename from app/src/main/java/se/leap/bitmaskclient/utils/DateHelper.java
rename to app/src/main/java/se/leap/bitmaskclient/base/utils/DateHelper.java
index 523c8c4c4e131448311416d4b6f6f309e75d3cb5..0476bf12feb3ff612b6214f0c1e5885245e5c685 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/DateHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/DateHelper.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.utils;
+package se.leap.bitmaskclient.base.utils;
 
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/FileHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/FileHelper.java
similarity index 96%
rename from app/src/main/java/se/leap/bitmaskclient/utils/FileHelper.java
rename to app/src/main/java/se/leap/bitmaskclient/base/utils/FileHelper.java
index ebcc32ba7a523608946adf4fa6a7bfa5638522c7..eb1c255c5bc83550cda278bc21e069cb940791b5 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/FileHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/FileHelper.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.utils;
+package se.leap.bitmaskclient.base.utils;
 
 import android.content.Context;
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/IPAddress.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/IPAddress.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/utils/IPAddress.java
rename to app/src/main/java/se/leap/bitmaskclient/base/utils/IPAddress.java
index 2e3ef59627fbca88c17ed354b5352f1c08525727..377617a4ce7315e56fe6ffdb914c2fcfeafdcb68 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/IPAddress.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/IPAddress.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.utils;
+package se.leap.bitmaskclient.base.utils;
 
 /*
  * Copyright (C) 2006-2008 Alfresco Software Limited.
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/InputStreamHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/InputStreamHelper.java
similarity index 93%
rename from app/src/main/java/se/leap/bitmaskclient/utils/InputStreamHelper.java
rename to app/src/main/java/se/leap/bitmaskclient/base/utils/InputStreamHelper.java
index 879966151e4922b2613a6c9358f7c38d8a60f692..77189dffc8979e0f0413300845ef536687c94005 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/InputStreamHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/InputStreamHelper.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.utils;
+package se.leap.bitmaskclient.base.utils;
 
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/KeyStoreHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/KeyStoreHelper.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/utils/KeyStoreHelper.java
rename to app/src/main/java/se/leap/bitmaskclient/base/utils/KeyStoreHelper.java
index 48d4cbad0de29366d8b91a6c805a51e2c7f3fb30..b0b28993f08aad7eb65b7b1ef55fb6568dbd5c8e 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/KeyStoreHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/KeyStoreHelper.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.utils;
+package se.leap.bitmaskclient.base.utils;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/app/src/main/java/se/leap/bitmaskclient/PRNGFixes.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PRNGFixes.java
similarity index 99%
rename from app/src/main/java/se/leap/bitmaskclient/PRNGFixes.java
rename to app/src/main/java/se/leap/bitmaskclient/base/utils/PRNGFixes.java
index 9e523751328e83d771814cde8ee1ff58b3b1191c..41b8cf35ee1761a7202cbb9839e46c41a31ab5e9 100644
--- a/app/src/main/java/se/leap/bitmaskclient/PRNGFixes.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PRNGFixes.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.base.utils;
 
 /*
  * This software is provided 'as-is', without any express or implied
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java
similarity index 88%
rename from app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
rename to app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java
index 5b62d0ffadb539cf7359194ebd2751092120fcfa..d31c7a206c2424be8f2557a532045782b2922bbb 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.utils;
+package se.leap.bitmaskclient.base.utils;
 
 import android.content.Context;
 import android.content.SharedPreferences;
@@ -13,26 +13,26 @@ import java.util.HashSet;
 import java.util.Set;
 
 import de.blinkt.openvpn.VpnProfile;
-import se.leap.bitmaskclient.Provider;
+import se.leap.bitmaskclient.base.models.Provider;
 
 import static android.content.Context.MODE_PRIVATE;
-import static se.leap.bitmaskclient.Constants.ALLOW_TETHERING_BLUETOOTH;
-import static se.leap.bitmaskclient.Constants.ALLOW_TETHERING_USB;
-import static se.leap.bitmaskclient.Constants.ALLOW_TETHERING_WIFI;
-import static se.leap.bitmaskclient.Constants.ALWAYS_ON_SHOW_DIALOG;
-import static se.leap.bitmaskclient.Constants.DEFAULT_SHARED_PREFS_BATTERY_SAVER;
-import static se.leap.bitmaskclient.Constants.EXCLUDED_APPS;
-import static se.leap.bitmaskclient.Constants.LAST_UPDATE_CHECK;
-import static se.leap.bitmaskclient.Constants.LAST_USED_PROFILE;
-import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED;
-import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.Constants.RESTART_ON_UPDATE;
-import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
-import static se.leap.bitmaskclient.Constants.SHOW_EXPERIMENTAL;
-import static se.leap.bitmaskclient.Constants.USE_IPv6_FIREWALL;
-import static se.leap.bitmaskclient.Constants.USE_PLUGGABLE_TRANSPORTS;
+import static se.leap.bitmaskclient.base.models.Constants.ALLOW_TETHERING_BLUETOOTH;
+import static se.leap.bitmaskclient.base.models.Constants.ALLOW_TETHERING_USB;
+import static se.leap.bitmaskclient.base.models.Constants.ALLOW_TETHERING_WIFI;
+import static se.leap.bitmaskclient.base.models.Constants.ALWAYS_ON_SHOW_DIALOG;
+import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_SHARED_PREFS_BATTERY_SAVER;
+import static se.leap.bitmaskclient.base.models.Constants.EXCLUDED_APPS;
+import static se.leap.bitmaskclient.base.models.Constants.LAST_UPDATE_CHECK;
+import static se.leap.bitmaskclient.base.models.Constants.LAST_USED_PROFILE;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_CONFIGURED;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_EIP_DEFINITION;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.models.Constants.RESTART_ON_UPDATE;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.base.models.Constants.SHOW_EXPERIMENTAL;
+import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL;
+import static se.leap.bitmaskclient.base.models.Constants.USE_PLUGGABLE_TRANSPORTS;
 
 /**
  * Created by cyberta on 18.03.18.
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/ViewHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java
similarity index 88%
rename from app/src/main/java/se/leap/bitmaskclient/utils/ViewHelper.java
rename to app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java
index 5f4fc2a6b70b2d6f84b6b6f99782a32eb2ceb227..23ca40e57ea2881cee0ef3e43f91e94e5291f17e 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/ViewHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.utils;
+package se.leap.bitmaskclient.base.utils;
 
 import android.content.Context;
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/views/IconCheckboxEntry.java b/app/src/main/java/se/leap/bitmaskclient/base/views/IconCheckboxEntry.java
similarity index 96%
rename from app/src/main/java/se/leap/bitmaskclient/views/IconCheckboxEntry.java
rename to app/src/main/java/se/leap/bitmaskclient/base/views/IconCheckboxEntry.java
index efe20b4cd200844baec0da27dda170a6540144b9..fdbd7dbd8632d5234a3cc9844683913254c68ed7 100644
--- a/app/src/main/java/se/leap/bitmaskclient/views/IconCheckboxEntry.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/views/IconCheckboxEntry.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.views;
+package se.leap.bitmaskclient.base.views;
 
 import android.annotation.TargetApi;
 import android.content.Context;
@@ -16,7 +16,7 @@ import android.widget.TextView;
 import butterknife.ButterKnife;
 import butterknife.InjectView;
 import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.fragments.TetheringDialog;
+import se.leap.bitmaskclient.base.fragments.TetheringDialog;
 
 
 public class IconCheckboxEntry extends LinearLayout {
diff --git a/app/src/main/java/se/leap/bitmaskclient/views/IconSwitchEntry.java b/app/src/main/java/se/leap/bitmaskclient/base/views/IconSwitchEntry.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/views/IconSwitchEntry.java
rename to app/src/main/java/se/leap/bitmaskclient/base/views/IconSwitchEntry.java
index c9b6024ddd05527677c2a9b6416a2c19b67d1184..1160986e503eb7eda6e39226152d2e33b813ae0f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/views/IconSwitchEntry.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/views/IconSwitchEntry.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.views;
+package se.leap.bitmaskclient.base.views;
 
 import android.annotation.TargetApi;
 import android.content.Context;
diff --git a/app/src/main/java/se/leap/bitmaskclient/views/IconTextEntry.java b/app/src/main/java/se/leap/bitmaskclient/base/views/IconTextEntry.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/views/IconTextEntry.java
rename to app/src/main/java/se/leap/bitmaskclient/base/views/IconTextEntry.java
index 7a1717e92533a8cde897e3057a4425ff4eda32b7..6b9bd760b0ff6034b921075da33b6b7c260d3bf9 100644
--- a/app/src/main/java/se/leap/bitmaskclient/views/IconTextEntry.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/views/IconTextEntry.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.views;
+package se.leap.bitmaskclient.base.views;
 
 import android.annotation.TargetApi;
 import android.content.Context;
diff --git a/app/src/main/java/se/leap/bitmaskclient/views/IconTextView.java b/app/src/main/java/se/leap/bitmaskclient/base/views/IconTextView.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/views/IconTextView.java
rename to app/src/main/java/se/leap/bitmaskclient/base/views/IconTextView.java
index 29c70859d7fe1b3ee67c6e44a5d3df5949ed31b8..1f64e483db132bb3be75879cc03fa781cbda1012 100644
--- a/app/src/main/java/se/leap/bitmaskclient/views/IconTextView.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/views/IconTextView.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.views;
+package se.leap.bitmaskclient.base.views;
 
 
 import android.content.Context;
diff --git a/app/src/main/java/se/leap/bitmaskclient/views/ProviderHeaderView.java b/app/src/main/java/se/leap/bitmaskclient/base/views/ProviderHeaderView.java
similarity index 97%
rename from app/src/main/java/se/leap/bitmaskclient/views/ProviderHeaderView.java
rename to app/src/main/java/se/leap/bitmaskclient/base/views/ProviderHeaderView.java
index 4fa3771b1a16c500328605065f3a93001e73040a..811a54a2a209c9d53ccbf3cd30c567635971cf7f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/views/ProviderHeaderView.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/views/ProviderHeaderView.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient.views;
+package se.leap.bitmaskclient.base.views;
 
 import android.content.Context;
 import androidx.annotation.DrawableRes;
@@ -13,7 +13,7 @@ import android.widget.RelativeLayout;
 
 import se.leap.bitmaskclient.R;
 
-import static se.leap.bitmaskclient.utils.ViewHelper.convertDimensionToPx;
+import static se.leap.bitmaskclient.base.utils.ViewHelper.convertDimensionToPx;
 
 /**
  * Created by cyberta on 29.06.18.
diff --git a/app/src/main/java/se/leap/bitmaskclient/views/VpnStateImage.java b/app/src/main/java/se/leap/bitmaskclient/base/views/VpnStateImage.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/views/VpnStateImage.java
rename to app/src/main/java/se/leap/bitmaskclient/base/views/VpnStateImage.java
index c0432edc653811ccc706cb13f4f1e8c082e32b41..2f8a444892600d5da5391b6cee928fa8ed491eb2 100644
--- a/app/src/main/java/se/leap/bitmaskclient/views/VpnStateImage.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/views/VpnStateImage.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.views;
+package se.leap.bitmaskclient.base.views;
 
 import android.content.Context;
 import androidx.constraintlayout.widget.ConstraintLayout;
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 e0c96ebb3e74d4e976099db2a5b6aeaee77298dd..e5cf70bea505a9efa3090b33e7a7b4ef1cd7c807 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
@@ -49,39 +49,39 @@ import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
 import de.blinkt.openvpn.core.OpenVPNService;
 import de.blinkt.openvpn.core.VpnStatus;
 import de.blinkt.openvpn.core.connection.Connection;
-import se.leap.bitmaskclient.OnBootReceiver;
-import se.leap.bitmaskclient.ProviderObservable;
+import se.leap.bitmaskclient.base.OnBootReceiver;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
 import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
 
 import static android.app.Activity.RESULT_CANCELED;
 import static android.app.Activity.RESULT_OK;
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN;
-import static se.leap.bitmaskclient.Constants.BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_CHECK_CERT_VALIDITY;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_CONFIGURE_TETHERING;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_IS_RUNNING;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START_ALWAYS_ON_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START_BLOCKING_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP_BLOCKING_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_EARLY_ROUTES;
-import static se.leap.bitmaskclient.Constants.EIP_N_CLOSEST_GATEWAY;
-import static se.leap.bitmaskclient.Constants.EIP_RECEIVER;
-import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE;
-import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_CHECK_CERT_VALIDITY;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_CONFIGURE_TETHERING;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_IS_RUNNING;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_ALWAYS_ON_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_BLOCKING_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP_BLOCKING_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_EARLY_ROUTES;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_N_CLOSEST_GATEWAY;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_RECEIVER;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
 import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid;
 import static se.leap.bitmaskclient.R.string.warning_client_parsing_error_gateways;
 import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_VPN_CERTIFICATE;
 import static se.leap.bitmaskclient.eip.EIP.EIPErrors.NO_MORE_GATEWAYS;
 import static se.leap.bitmaskclient.eip.EipResultBroadcast.tellToReceiverOrBroadcast;
-import static se.leap.bitmaskclient.utils.ConfigHelper.ensureNotOnMainThread;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.getUsePluggableTransports;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePluggableTransports;
 
 /**
  * EIP is the abstract base class for interacting with and managing the Encrypted
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java
index 25450f5664f53d549a72fb3dab4cc08ba5d2b0b6..39d4e33e74f43188fee6422cbc28a831dbdda666 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java
@@ -11,14 +11,14 @@ import androidx.annotation.VisibleForTesting;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_CHECK_CERT_VALIDITY;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_CONFIGURE_TETHERING;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START_BLOCKING_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP;
-import static se.leap.bitmaskclient.Constants.EIP_EARLY_ROUTES;
-import static se.leap.bitmaskclient.Constants.EIP_N_CLOSEST_GATEWAY;
-import static se.leap.bitmaskclient.Constants.EIP_RECEIVER;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_CHECK_CERT_VALIDITY;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_CONFIGURE_TETHERING;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_BLOCKING_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_EARLY_ROUTES;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_N_CLOSEST_GATEWAY;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_RECEIVER;
 
 /**
  * Use this class to send commands to EIP
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipResultBroadcast.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipResultBroadcast.java
index 92d1338c9bf8cbb7abedd7404193f642d39f1975..68d9c8ad8ef506b23146df505cfcf4df86c3b7c4 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EipResultBroadcast.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipResultBroadcast.java
@@ -8,10 +8,10 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 import android.util.Log;
 
 import static android.content.Intent.CATEGORY_DEFAULT;
-import static se.leap.bitmaskclient.Constants.BROADCAST_EIP_EVENT;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
-import static se.leap.bitmaskclient.Constants.EIP_REQUEST;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_EIP_EVENT;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_REQUEST;
 
 public class EipResultBroadcast {
     private static final String TAG = EipResultBroadcast.class.getSimpleName();
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipSetupListener.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupListener.java
similarity index 85%
rename from app/src/main/java/se/leap/bitmaskclient/EipSetupListener.java
rename to app/src/main/java/se/leap/bitmaskclient/eip/EipSetupListener.java
index 71e2fd5265603fb2e4ed0edafe5afc6532c317d0..13d9bdecb82c78857993d34f1b8ff233467d9c69 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipSetupListener.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupListener.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.eip;
 
 import android.content.Intent;
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java
similarity index 88%
rename from app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java
rename to app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java
index e365c8574430e9dbbef5eebb725af8b9392d908e..1c101e2d3cbdd6bba57ec8ec6fe5adf10906d917 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java
@@ -15,7 +15,7 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.eip;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -38,40 +38,39 @@ import de.blinkt.openvpn.VpnProfile;
 import de.blinkt.openvpn.core.ConnectionStatus;
 import de.blinkt.openvpn.core.LogItem;
 import de.blinkt.openvpn.core.VpnStatus;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.ProviderAPI;
+import se.leap.bitmaskclient.providersetup.ProviderAPICommand;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
 import se.leap.bitmaskclient.appUpdate.DownloadServiceCommand;
-import se.leap.bitmaskclient.eip.EIP;
-import se.leap.bitmaskclient.eip.EipCommand;
-import se.leap.bitmaskclient.eip.EipStatus;
-import se.leap.bitmaskclient.eip.Gateway;
-import se.leap.bitmaskclient.eip.GatewaysManager;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
 
 import static android.app.Activity.RESULT_CANCELED;
 import static android.content.Intent.CATEGORY_DEFAULT;
 import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET;
 import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NOTCONNECTED;
-import static se.leap.bitmaskclient.Constants.BROADCAST_EIP_EVENT;
-import static se.leap.bitmaskclient.Constants.BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT;
-import static se.leap.bitmaskclient.Constants.BROADCAST_PROVIDER_API_EVENT;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_PREPARE_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START_ALWAYS_ON_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_EARLY_ROUTES;
-import static se.leap.bitmaskclient.Constants.EIP_REQUEST;
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE;
-import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE;
-import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON;
-import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_EIP_EVENT;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_PROVIDER_API_EVENT;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_PREPARE_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_ALWAYS_ON_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_EARLY_ROUTES;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_REQUEST;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON;
 import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.CHECK_VERSION_FILE;
 
 /**
  * Created by cyberta on 05.12.18.
  */
-class EipSetupObserver extends BroadcastReceiver implements VpnStatus.StateListener, VpnStatus.LogListener {
+public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.StateListener, VpnStatus.LogListener {
 
     private static final String TAG = EipSetupObserver.class.getName();
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
index f3eea41509ae7675571629e1e0a56f2eda62bdbb..1df54e6e97439afb9eec310fb4983185ccd6b86f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
@@ -32,16 +32,16 @@ import java.util.Set;
 import de.blinkt.openvpn.VpnProfile;
 import de.blinkt.openvpn.core.ConfigParser;
 import de.blinkt.openvpn.core.connection.Connection;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
-
-import static se.leap.bitmaskclient.Constants.HOST;
-import static se.leap.bitmaskclient.Constants.IP_ADDRESS;
-import static se.leap.bitmaskclient.Constants.LOCATION;
-import static se.leap.bitmaskclient.Constants.LOCATIONS;
-import static se.leap.bitmaskclient.Constants.NAME;
-import static se.leap.bitmaskclient.Constants.OPENVPN_CONFIGURATION;
-import static se.leap.bitmaskclient.Constants.TIMEZONE;
-import static se.leap.bitmaskclient.Constants.VERSION;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
+
+import static se.leap.bitmaskclient.base.models.Constants.HOST;
+import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS;
+import static se.leap.bitmaskclient.base.models.Constants.LOCATION;
+import static se.leap.bitmaskclient.base.models.Constants.LOCATIONS;
+import static se.leap.bitmaskclient.base.models.Constants.NAME;
+import static se.leap.bitmaskclient.base.models.Constants.OPENVPN_CONFIGURATION;
+import static se.leap.bitmaskclient.base.models.Constants.TIMEZONE;
+import static se.leap.bitmaskclient.base.models.Constants.VERSION;
 
 /**
  * Gateway provides objects defining gateways and their metadata.
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
index 0ba0f20725b78d1a39aea0090b1f5c35b073da63..33fd3c21615a88598a2922d6f1d4f5d41774d22d 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
@@ -8,7 +8,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 
-import static se.leap.bitmaskclient.utils.ConfigHelper.getCurrentTimezone;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.getCurrentTimezone;
 
 public class GatewaySelector {
     private final static String TAG = GatewaySelector.class.getSimpleName();
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 354fd9a3aca00b9afe3daaa7adf5fdc2f28f8364..a5d4c416481308f5c5eb57cc9e392293d6022310 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -35,15 +35,15 @@ import de.blinkt.openvpn.VpnProfile;
 import de.blinkt.openvpn.core.ConfigParser;
 import de.blinkt.openvpn.core.VpnStatus;
 import de.blinkt.openvpn.core.connection.Connection;
-import se.leap.bitmaskclient.Provider;
-import se.leap.bitmaskclient.ProviderObservable;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
 
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN;
-import static se.leap.bitmaskclient.Constants.GATEWAYS;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.getUsePluggableTransports;
+import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePluggableTransports;
 
 /**
  * @author parmegv
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java
index 9a3c8f8544a9588dae8849477fff5071bb234885..e69054480e7f3283f5f4c0bd2e0f07acfd9db12c 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java
@@ -6,7 +6,7 @@ import android.net.VpnService;
 import android.os.Build;
 import android.os.Bundle;
 
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START_BLOCKING_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_BLOCKING_VPN;
 
 public class VoidVpnLauncher extends Activity {
 
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 78deea0bdc49af10c1e576eac771ce91be93701a..7703849222d1af7a3eee859ab789914f1d3bf87d 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java
@@ -33,14 +33,13 @@ import java.util.Observer;
 import de.blinkt.openvpn.core.ConnectionStatus;
 import de.blinkt.openvpn.core.VpnStatus;
 import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.VpnNotificationManager;
-
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START_ALWAYS_ON_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START_BLOCKING_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP_BLOCKING_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_IS_ALWAYS_ON;
-import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
-import static se.leap.bitmaskclient.utils.ConfigHelper.getProviderFormattedString;
+
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_ALWAYS_ON_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_BLOCKING_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP_BLOCKING_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_IS_ALWAYS_ON;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString;
 
 
 public class VoidVpnService extends VpnService implements Observer, VpnNotificationManager.VpnServiceCallback {
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java
index 839047297cdc6cf0e59b68dfe719199e443978ef..c747b7314529c65784817199f2f5c9f84741a2b4 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java
@@ -22,7 +22,7 @@ import java.security.cert.X509Certificate;
 import java.util.Calendar;
 import java.util.Date;
 
-import se.leap.bitmaskclient.utils.ConfigHelper;
+import se.leap.bitmaskclient.base.utils.ConfigHelper;
 
 public class VpnCertificateValidator {
     public final static String TAG = VpnCertificateValidator.class.getSimpleName();
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
index 08e219c7806cf66085e09fb98976c1cc39ab1f56..51069d6d87923a208e66eb90d8c95f84b8778355 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
@@ -30,21 +30,21 @@ import java.util.Iterator;
 import de.blinkt.openvpn.VpnProfile;
 import de.blinkt.openvpn.core.ConfigParser;
 import de.blinkt.openvpn.core.connection.Connection;
-import se.leap.bitmaskclient.Provider;
+import se.leap.bitmaskclient.base.models.Provider;
 import se.leap.bitmaskclient.pluggableTransports.Obfs4Options;
 
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN;
-import static se.leap.bitmaskclient.Constants.CAPABILITIES;
-import static se.leap.bitmaskclient.Constants.IP_ADDRESS;
-import static se.leap.bitmaskclient.Constants.OPTIONS;
-import static se.leap.bitmaskclient.Constants.PORTS;
-import static se.leap.bitmaskclient.Constants.PROTOCOLS;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.Constants.REMOTE;
-import static se.leap.bitmaskclient.Constants.TRANSPORT;
-import static se.leap.bitmaskclient.Constants.TYPE;
+import static se.leap.bitmaskclient.base.models.Constants.CAPABILITIES;
+import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS;
+import static se.leap.bitmaskclient.base.models.Constants.OPTIONS;
+import static se.leap.bitmaskclient.base.models.Constants.PORTS;
+import static se.leap.bitmaskclient.base.models.Constants.PROTOCOLS;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.models.Constants.REMOTE;
+import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT;
+import static se.leap.bitmaskclient.base.models.Constants.TYPE;
 import static se.leap.bitmaskclient.pluggableTransports.Dispatcher.DISPATCHER_IP;
 import static se.leap.bitmaskclient.pluggableTransports.Dispatcher.DISPATCHER_PORT;
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/VpnNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java
similarity index 97%
rename from app/src/main/java/se/leap/bitmaskclient/VpnNotificationManager.java
rename to app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java
index 290a9aa9e7b56e868923f903eb01ba7d6b84a970..b3ed5394356bb2eca285a7f6ecfeb3332582fa5c 100644
--- a/app/src/main/java/se/leap/bitmaskclient/VpnNotificationManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.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.eip;
 
 import android.annotation.TargetApi;
 import android.app.Notification;
@@ -39,7 +39,9 @@ import android.widget.RemoteViews;
 import de.blinkt.openvpn.LaunchVPN;
 import de.blinkt.openvpn.core.ConnectionStatus;
 import de.blinkt.openvpn.core.OpenVPNService;
-import se.leap.bitmaskclient.eip.VoidVpnService;
+import se.leap.bitmaskclient.base.MainActivity;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.base.StartActivity;
 
 import static android.os.Build.VERSION_CODES.O;
 import static androidx.core.app.NotificationCompat.PRIORITY_HIGH;
@@ -48,9 +50,9 @@ import static androidx.core.app.NotificationCompat.PRIORITY_MIN;
 import static android.text.TextUtils.isEmpty;
 import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK;
 import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT;
-import static se.leap.bitmaskclient.Constants.ASK_TO_CANCEL_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP_BLOCKING_VPN;
-import static se.leap.bitmaskclient.MainActivity.ACTION_SHOW_VPN_FRAGMENT;
+import static se.leap.bitmaskclient.base.models.Constants.ASK_TO_CANCEL_VPN;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP_BLOCKING_VPN;
+import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT;
 
 /**
  * Created by cyberta on 14.01.18.
diff --git a/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallManager.java b/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallManager.java
index ace8a2987c9f76a6542174bde9e04791eeaec4cd..dcb4a74318c5dde886f5135ce580c83ff8191fb9 100644
--- a/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallManager.java
@@ -28,7 +28,7 @@ import de.blinkt.openvpn.core.VpnStatus;
 import se.leap.bitmaskclient.R;
 import se.leap.bitmaskclient.tethering.TetheringObservable;
 import se.leap.bitmaskclient.tethering.TetheringState;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
 
 public class FirewallManager implements FirewallCallback, Observer {
     public static String BITMASK_CHAIN = "bitmask_fw";
diff --git a/app/src/main/java/se/leap/bitmaskclient/firewall/SetupTetheringTask.java b/app/src/main/java/se/leap/bitmaskclient/firewall/SetupTetheringTask.java
index edf79add18eeec05a1c1d421ef57348918d0133c..53118cae7f8a56a935d16c2c2df919986df27911 100644
--- a/app/src/main/java/se/leap/bitmaskclient/firewall/SetupTetheringTask.java
+++ b/app/src/main/java/se/leap/bitmaskclient/firewall/SetupTetheringTask.java
@@ -29,7 +29,7 @@ import se.leap.bitmaskclient.tethering.TetheringState;
 
 import static se.leap.bitmaskclient.firewall.FirewallManager.BITMASK_FORWARD;
 import static se.leap.bitmaskclient.firewall.FirewallManager.BITMASK_POSTROUTING;
-import static se.leap.bitmaskclient.utils.Cmd.runBlockingCmd;
+import static se.leap.bitmaskclient.base.utils.Cmd.runBlockingCmd;
 
 public class SetupTetheringTask extends AsyncTask<Void, Boolean, Boolean> {
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/firewall/ShutdownIPv6FirewallTask.java b/app/src/main/java/se/leap/bitmaskclient/firewall/ShutdownIPv6FirewallTask.java
index 63d6074d7f4af937fd746a4710ade24387e734e3..c14c579e3756be3d71126b065fb27b77875d73d2 100644
--- a/app/src/main/java/se/leap/bitmaskclient/firewall/ShutdownIPv6FirewallTask.java
+++ b/app/src/main/java/se/leap/bitmaskclient/firewall/ShutdownIPv6FirewallTask.java
@@ -22,7 +22,7 @@ import android.util.Log;
 import java.lang.ref.WeakReference;
 
 import static se.leap.bitmaskclient.firewall.FirewallManager.BITMASK_CHAIN;
-import static se.leap.bitmaskclient.utils.Cmd.runBlockingCmd;
+import static se.leap.bitmaskclient.base.utils.Cmd.runBlockingCmd;
 
 class ShutdownIPv6FirewallTask extends AsyncTask<Void, Boolean, Boolean> {
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/firewall/ShutdownTetheringTask.java b/app/src/main/java/se/leap/bitmaskclient/firewall/ShutdownTetheringTask.java
index dcb3ccba3d58c131d014faaa3fcd610aed14dc69..d867009add1b48489ca1ca29148c7e1bbb117323 100644
--- a/app/src/main/java/se/leap/bitmaskclient/firewall/ShutdownTetheringTask.java
+++ b/app/src/main/java/se/leap/bitmaskclient/firewall/ShutdownTetheringTask.java
@@ -27,7 +27,7 @@ import se.leap.bitmaskclient.tethering.TetheringState;
 
 import static se.leap.bitmaskclient.firewall.FirewallManager.BITMASK_FORWARD;
 import static se.leap.bitmaskclient.firewall.FirewallManager.BITMASK_POSTROUTING;
-import static se.leap.bitmaskclient.utils.Cmd.runBlockingCmd;
+import static se.leap.bitmaskclient.base.utils.Cmd.runBlockingCmd;
 
 public class ShutdownTetheringTask extends AsyncTask<Void, Boolean, Boolean> {
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/firewall/StartIPv6FirewallTask.java b/app/src/main/java/se/leap/bitmaskclient/firewall/StartIPv6FirewallTask.java
index b01270e0171bda4b4f153dfbb855bcecddd5ff90..f2c8b739361220de1eb6e967cb35c6a043e87f66 100644
--- a/app/src/main/java/se/leap/bitmaskclient/firewall/StartIPv6FirewallTask.java
+++ b/app/src/main/java/se/leap/bitmaskclient/firewall/StartIPv6FirewallTask.java
@@ -22,7 +22,7 @@ import android.util.Log;
 import java.lang.ref.WeakReference;
 
 import static se.leap.bitmaskclient.firewall.FirewallManager.BITMASK_CHAIN;
-import static se.leap.bitmaskclient.utils.Cmd.runBlockingCmd;
+import static se.leap.bitmaskclient.base.utils.Cmd.runBlockingCmd;
 
 class StartIPv6FirewallTask extends AsyncTask<Void, Boolean, Boolean> {
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java
similarity index 95%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java
index bec1613903a5aa756d7a252f8d1c6de66eaddf4f..23c750a3d717b1f9be7254a02db0540704683e5a 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.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.providersetup;
 
 import android.annotation.SuppressLint;
 import android.content.Context;
@@ -25,7 +25,9 @@ import androidx.annotation.NonNull;
 import androidx.core.app.JobIntentService;
 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 
-import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
+import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator;
+
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
 
 /**
  * Implements HTTP api methods (encapsulated in {{@link ProviderApiManager}})
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPICommand.java
similarity index 95%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPICommand.java
index 8de90af25ff00749f13be97594ebfba03d0996f2..79a107d108023818c3e4526136fb292cd91df730 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPICommand.java
@@ -1,14 +1,16 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.ResultReceiver;
-import android.util.Log;
 
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import se.leap.bitmaskclient.base.models.Constants;
+import se.leap.bitmaskclient.base.models.Provider;
+
 public class ProviderAPICommand {
     private static final String TAG = ProviderAPICommand.class.getSimpleName();
     private Context context;
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiConnector.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiConnector.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderApiConnector.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiConnector.java
index 84f21343b33494ae1cf544f795fdf810f0364b86..ba902566771350cd01085bcb8f69627bc6154aee 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiConnector.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiConnector.java
@@ -15,7 +15,7 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import androidx.annotation.NonNull;
 import android.util.Pair;
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java
similarity index 88%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java
index 025e7aab6891a50704132519164643eb6cd8943d..8a0c8f025767ff782781ac5cfe448cba7a27c86a 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java
@@ -15,7 +15,7 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -53,57 +53,64 @@ import javax.net.ssl.SSLHandshakeException;
 import javax.net.ssl.SSLPeerUnverifiedException;
 
 import okhttp3.OkHttpClient;
-import se.leap.bitmaskclient.Constants.CREDENTIAL_ERRORS;
-import se.leap.bitmaskclient.utils.ConfigHelper;
-
-import static se.leap.bitmaskclient.Constants.BROADCAST_PROVIDER_API_EVENT;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
-import static se.leap.bitmaskclient.Constants.CREDENTIALS_PASSWORD;
-import static se.leap.bitmaskclient.Constants.CREDENTIALS_USERNAME;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.Provider.CA_CERT;
-import static se.leap.bitmaskclient.Provider.GEOIP_URL;
-import static se.leap.bitmaskclient.Provider.PROVIDER_API_IP;
-import static se.leap.bitmaskclient.Provider.PROVIDER_IP;
-import static se.leap.bitmaskclient.ProviderAPI.BACKEND_ERROR_KEY;
-import static se.leap.bitmaskclient.ProviderAPI.BACKEND_ERROR_MESSAGE;
-import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE;
-import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON;
-import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_GEOIP_JSON;
-import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_SERVICE_JSON;
-import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.ERRORID;
-import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
-import static se.leap.bitmaskclient.ProviderAPI.FAILED_LOGIN;
-import static se.leap.bitmaskclient.ProviderAPI.FAILED_SIGNUP;
-import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE;
-import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON;
-import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.LOGOUT_FAILED;
-import static se.leap.bitmaskclient.ProviderAPI.LOG_IN;
-import static se.leap.bitmaskclient.ProviderAPI.LOG_OUT;
-import static se.leap.bitmaskclient.ProviderAPI.PARAMETERS;
-import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_NOK;
-import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_OK;
-import static se.leap.bitmaskclient.ProviderAPI.RECEIVER_KEY;
-import static se.leap.bitmaskclient.ProviderAPI.SET_UP_PROVIDER;
-import static se.leap.bitmaskclient.ProviderAPI.SIGN_UP;
-import static se.leap.bitmaskclient.ProviderAPI.SUCCESSFUL_LOGIN;
-import static se.leap.bitmaskclient.ProviderAPI.SUCCESSFUL_LOGOUT;
-import static se.leap.bitmaskclient.ProviderAPI.SUCCESSFUL_SIGNUP;
-import static se.leap.bitmaskclient.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.UPDATE_PROVIDER_DETAILS;
-import static se.leap.bitmaskclient.ProviderAPI.USER_MESSAGE;
-import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING;
-import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON;
-import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_INVALID_CERTIFICATE;
+import se.leap.bitmaskclient.base.models.Constants.CREDENTIAL_ERRORS;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator;
+import se.leap.bitmaskclient.providersetup.models.LeapSRPSession;
+import se.leap.bitmaskclient.providersetup.models.SrpCredentials;
+import se.leap.bitmaskclient.providersetup.models.SrpRegistrationData;
+import se.leap.bitmaskclient.base.utils.ConfigHelper;
+
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_PROVIDER_API_EVENT;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.CREDENTIALS_PASSWORD;
+import static se.leap.bitmaskclient.base.models.Constants.CREDENTIALS_USERNAME;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.models.Provider.CA_CERT;
+import static se.leap.bitmaskclient.base.models.Provider.GEOIP_URL;
+import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_API_IP;
+import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_IP;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.BACKEND_ERROR_KEY;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.BACKEND_ERROR_MESSAGE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_GEOIP_JSON;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_SERVICE_JSON;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORID;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.FAILED_LOGIN;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.FAILED_SIGNUP;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.LOGOUT_FAILED;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.LOG_IN;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.LOG_OUT;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.PARAMETERS;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_NOK;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_OK;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.RECEIVER_KEY;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.SET_UP_PROVIDER;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.SIGN_UP;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_LOGIN;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_LOGOUT;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_SIGNUP;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_PROVIDER_DETAILS;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_INVALID_CERTIFICATE;
 import static se.leap.bitmaskclient.R.string.certificate_error;
 import static se.leap.bitmaskclient.R.string.error_io_exception_user_message;
 import static se.leap.bitmaskclient.R.string.error_json_exception_user_message;
@@ -115,11 +122,11 @@ import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid;
 import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_cert;
 import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_details;
 import static se.leap.bitmaskclient.R.string.warning_expired_provider_cert;
-import static se.leap.bitmaskclient.utils.ConfigHelper.getFingerprintFromCertificate;
-import static se.leap.bitmaskclient.utils.ConfigHelper.getProviderFormattedString;
-import static se.leap.bitmaskclient.utils.ConfigHelper.parseRsaKeyFromString;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.deleteProviderDetailsFromPreferences;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.getFromPersistedProvider;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.getFingerprintFromCertificate;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.parseRsaKeyFromString;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.deleteProviderDetailsFromPreferences;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getFromPersistedProvider;
 
 /**
  * Implements the logic of the http api calls. The methods of this class needs to be called from
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiSetupBroadcastReceiver.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java
similarity index 91%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderApiSetupBroadcastReceiver.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java
index 890d3b67661633592a3552617df6a13d96b84619..710aee0f51d7bdc87b222ac49dd69ddf02985f49 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiSetupBroadcastReceiver.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.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.providersetup;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -24,7 +24,10 @@ import android.util.Log;
 
 import java.lang.ref.WeakReference;
 
-import se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState;
+import se.leap.bitmaskclient.base.models.Constants;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState;
+import se.leap.bitmaskclient.providersetup.activities.ProviderListBaseActivity;
 
 /**
  * Broadcast receiver that handles callback intents of ProviderApi during provider setup.
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListAdapter.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderListAdapter.java
similarity index 87%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderListAdapter.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderListAdapter.java
index 6672c57594d087c29c5d478d75c2ca412f574802..76ee33f2ee0f091a45af618babf3bdfae6c30611 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderListAdapter.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderListAdapter.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import android.view.LayoutInflater;
 
@@ -6,6 +6,8 @@ import com.pedrogomez.renderers.AdapteeCollection;
 import com.pedrogomez.renderers.RendererAdapter;
 import com.pedrogomez.renderers.RendererBuilder;
 
+import se.leap.bitmaskclient.base.models.Provider;
+
 public class ProviderListAdapter extends RendererAdapter<Provider> {
     public ProviderListAdapter(LayoutInflater layoutInflater, RendererBuilder rendererBuilder,
                                AdapteeCollection<Provider> collection) {
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java
similarity index 93%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java
index c23ad2704b6ffb3ea228950414b4670d46fd2753..d33a175f8c0ee6abe88957e973170b3bcb95a40f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import android.content.res.AssetManager;
 import androidx.annotation.VisibleForTesting;
@@ -20,14 +20,16 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
-import static se.leap.bitmaskclient.Provider.GEOIP_URL;
-import static se.leap.bitmaskclient.Provider.MAIN_URL;
-import static se.leap.bitmaskclient.Provider.PROVIDER_API_IP;
-import static se.leap.bitmaskclient.Provider.PROVIDER_IP;
-import static se.leap.bitmaskclient.utils.FileHelper.createFile;
-import static se.leap.bitmaskclient.utils.FileHelper.persistFile;
-import static se.leap.bitmaskclient.utils.InputStreamHelper.getInputStreamFrom;
-import static se.leap.bitmaskclient.utils.InputStreamHelper.loadInputStreamAsString;
+import se.leap.bitmaskclient.base.models.Provider;
+
+import static se.leap.bitmaskclient.base.models.Provider.GEOIP_URL;
+import static se.leap.bitmaskclient.base.models.Provider.MAIN_URL;
+import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_API_IP;
+import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_IP;
+import static se.leap.bitmaskclient.base.utils.FileHelper.createFile;
+import static se.leap.bitmaskclient.base.utils.FileHelper.persistFile;
+import static se.leap.bitmaskclient.base.utils.InputStreamHelper.getInputStreamFrom;
+import static se.leap.bitmaskclient.base.utils.InputStreamHelper.loadInputStreamAsString;
 
 /**
  * Created by parmegv on 4/12/14.
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderRenderer.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderRenderer.java
similarity index 90%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderRenderer.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderRenderer.java
index 795c8e824c8c345fb1c03e305484cd994144c49f..52ee46560615eaae1ee5c18bf75d33fe488840c9 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderRenderer.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderRenderer.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import android.content.*;
 import android.view.*;
@@ -7,6 +7,8 @@ import android.widget.*;
 import com.pedrogomez.renderers.*;
 
 import butterknife.*;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.R;
 
 /**
  * Created by parmegv on 4/12/14.
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderRendererBuilder.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderRendererBuilder.java
similarity index 80%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderRendererBuilder.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderRendererBuilder.java
index 5a6e857d9f2a32cbef123b013eba4ff133b7ceb5..7d2b47428424991393cff2d85e5bf9a82dbc3cf1 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderRendererBuilder.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderRendererBuilder.java
@@ -1,9 +1,11 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import com.pedrogomez.renderers.*;
 
 import java.util.*;
 
+import se.leap.bitmaskclient.base.models.Provider;
+
 /**
  * Created by parmegv on 4/12/14.
  */
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupFailedDialog.java
similarity index 93%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupFailedDialog.java
index d64f34d847d634892376900b807de13b55dd309b..947d118291f40549c0765bcd90692784874cb900 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupFailedDialog.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.providersetup;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -27,10 +27,13 @@ import androidx.fragment.app.DialogFragment;
 
 import org.json.JSONObject;
 
-import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.DEFAULT;
-import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.valueOf;
-import static se.leap.bitmaskclient.ProviderAPI.ERRORID;
-import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.R;
+
+import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.DEFAULT;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.valueOf;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORID;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS;
 
 /**
  * Implements a dialog to show why a download failed.
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupInterface.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupInterface.java
similarity index 93%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderSetupInterface.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupInterface.java
index 9cf4dc333dd3280b8dff5c4a021054cfc395734f..5b5c94b43e1969f240c649ed518699015183e16f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupInterface.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupInterface.java
@@ -14,10 +14,12 @@
  * 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.providersetup;
 
 import android.os.Bundle;
 
+import se.leap.bitmaskclient.base.models.Provider;
+
 /**
  * Created by cyberta on 17.08.18.
  */
diff --git a/app/src/main/java/se/leap/bitmaskclient/AbstractProviderDetailActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/AbstractProviderDetailActivity.java
similarity index 91%
rename from app/src/main/java/se/leap/bitmaskclient/AbstractProviderDetailActivity.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/activities/AbstractProviderDetailActivity.java
index a9f156a2b49d6dd18aae5d66c900b48589a39314..b7325e03bd9322f53616edad6d6e218f4cbbe3ac 100644
--- a/app/src/main/java/se/leap/bitmaskclient/AbstractProviderDetailActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/AbstractProviderDetailActivity.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup.activities;
 
 import android.content.Intent;
 import android.os.Bundle;
@@ -12,9 +12,11 @@ import android.widget.TextView;
 import java.util.ArrayList;
 
 import butterknife.InjectView;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.R;
 
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP;
 
 public abstract class AbstractProviderDetailActivity extends ConfigWizardBaseActivity {
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/AddProviderBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/AddProviderBaseActivity.java
similarity index 94%
rename from app/src/main/java/se/leap/bitmaskclient/AddProviderBaseActivity.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/activities/AddProviderBaseActivity.java
index e0bb0061bc4b48713ce88a65e927f8ac9f8cf585..0031f48ddea2827f730800ce29e3a39122055d69 100644
--- a/app/src/main/java/se/leap/bitmaskclient/AddProviderBaseActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/AddProviderBaseActivity.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup.activities;
 
 import android.content.Intent;
 import android.os.Bundle;
@@ -10,8 +10,9 @@ import android.view.View;
 import android.widget.Button;
 
 import butterknife.InjectView;
+import se.leap.bitmaskclient.R;
 
-import static se.leap.bitmaskclient.ProviderListBaseActivity.EXTRAS_KEY_INVALID_URL;
+import static se.leap.bitmaskclient.providersetup.activities.ProviderListBaseActivity.EXTRAS_KEY_INVALID_URL;
 
 /**
  * Created by cyberta on 30.06.18.
diff --git a/app/src/main/java/se/leap/bitmaskclient/ButterKnifeActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ButterKnifeActivity.java
similarity index 96%
rename from app/src/main/java/se/leap/bitmaskclient/ButterKnifeActivity.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ButterKnifeActivity.java
index 4f27f88a8d8ca38de1c735e3e70abdcec212baad..22edd9eedb88ea90299fb33b6b2ece1291eac7d7 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ButterKnifeActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ButterKnifeActivity.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.providersetup.activities;
 
 import androidx.appcompat.app.AppCompatActivity;
 import android.view.View;
diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java
similarity index 96%
rename from app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java
index 2d163859b9f83da6a0a63801cded089e9945f482..3712c5443e257f82ac5a437ebc139bc56e3bec42 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup.activities;
 
 import android.content.SharedPreferences;
 import android.graphics.PorterDuff;
@@ -20,13 +20,15 @@ import android.widget.ProgressBar;
 
 import butterknife.InjectView;
 import butterknife.Optional;
-import se.leap.bitmaskclient.views.ProviderHeaderView;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.base.views.ProviderHeaderView;
 
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
 
 /**
  * Base Activity for configuration wizard activities
diff --git a/app/src/main/java/se/leap/bitmaskclient/CustomProviderSetupActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CustomProviderSetupActivity.java
similarity index 84%
rename from app/src/main/java/se/leap/bitmaskclient/CustomProviderSetupActivity.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CustomProviderSetupActivity.java
index 0974f4277e0f4f9c9e3feb9041f7080ce8488d57..161c53d3faf763dcefee4583dd316cfcecd309ab 100644
--- a/app/src/main/java/se/leap/bitmaskclient/CustomProviderSetupActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CustomProviderSetupActivity.java
@@ -14,17 +14,22 @@
  * 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.providersetup.activities;
 
 import android.content.Intent;
 import android.os.Bundle;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
-import static se.leap.bitmaskclient.ProviderAPI.SET_UP_PROVIDER;
-import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER;
-import static se.leap.bitmaskclient.utils.ConfigHelper.preferAnonymousUsage;
+import se.leap.bitmaskclient.BuildConfig;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.ProviderAPICommand;
+import se.leap.bitmaskclient.R;
+
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.SET_UP_PROVIDER;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.preferAnonymousUsage;
 
 /**
  * Created by cyberta on 17.08.18.
diff --git a/app/src/main/java/se/leap/bitmaskclient/LoginActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/LoginActivity.java
similarity index 88%
rename from app/src/main/java/se/leap/bitmaskclient/LoginActivity.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/activities/LoginActivity.java
index 15166c679633083e2700c98c027f0543c3133ba9..a8bac6d888c63576cc61951c1f5613e12f306a3e 100644
--- a/app/src/main/java/se/leap/bitmaskclient/LoginActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/LoginActivity.java
@@ -1,9 +1,10 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup.activities;
 
 import android.os.Bundle;
 import androidx.annotation.Nullable;
 
 import butterknife.OnClick;
+import se.leap.bitmaskclient.R;
 
 /**
  * Activity to login to chosen Provider
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderCredentialsBaseActivity.java
similarity index 94%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderCredentialsBaseActivity.java
index c61caeada16332783246ba992b82ee435044b9e2..91d0de566f8a653f99cf7e2f7de5f01e78e68258 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderCredentialsBaseActivity.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.providersetup.activities;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -45,22 +45,26 @@ import org.json.JSONException;
 
 import butterknife.InjectView;
 import butterknife.OnClick;
-import se.leap.bitmaskclient.Constants.CREDENTIAL_ERRORS;
+import se.leap.bitmaskclient.base.models.Constants.CREDENTIAL_ERRORS;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.ProviderAPI;
+import se.leap.bitmaskclient.providersetup.ProviderAPICommand;
+import se.leap.bitmaskclient.R;
 
 import static android.text.TextUtils.isEmpty;
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
 import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
-import static se.leap.bitmaskclient.Constants.BROADCAST_PROVIDER_API_EVENT;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
-import static se.leap.bitmaskclient.Constants.CREDENTIALS_PASSWORD;
-import static se.leap.bitmaskclient.Constants.CREDENTIALS_USERNAME;
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.LOG_IN;
-import static se.leap.bitmaskclient.ProviderAPI.SIGN_UP;
-import static se.leap.bitmaskclient.ProviderAPI.USER_MESSAGE;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_PROVIDER_API_EVENT;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.CREDENTIALS_PASSWORD;
+import static se.leap.bitmaskclient.base.models.Constants.CREDENTIALS_USERNAME;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.LOG_IN;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.SIGN_UP;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE;
 
 /**
  * Base Activity for activities concerning a provider interaction
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderListBaseActivity.java
similarity index 87%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderListBaseActivity.java
index 44258a7b5c058c0e2a93f141f2f81ac8866169a0..46a40d118ab94e0364142a3555c439e2bd96279f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderListBaseActivity.java
@@ -15,7 +15,7 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup.activities;
 
 import android.content.Intent;
 import android.os.Bundle;
@@ -32,11 +32,18 @@ import javax.inject.Inject;
 
 import butterknife.InjectView;
 import butterknife.OnItemClick;
-
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_ADD_PROVIDER;
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
-import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER;
-import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SHOW_FAILED_DIALOG;
+import se.leap.bitmaskclient.providersetup.AddProviderActivity;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.ProviderListActivity;
+import se.leap.bitmaskclient.providersetup.ProviderRenderer;
+import se.leap.bitmaskclient.providersetup.ProviderRendererBuilder;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.providersetup.ProviderListAdapter;
+
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_ADD_PROVIDER;
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.SHOW_FAILED_DIALOG;
 
 /**
  * abstract base Activity that builds and shows the list of known available providers.
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java
similarity index 81%
rename from app/src/main/java/se/leap/bitmaskclient/ProviderSetupBaseActivity.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java
index 0994927f8f7d1f3687357578e1e0ae74c330b5b4..e54fb048a4f0850599d8ce48fdbf21a66f08bda4 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupBaseActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.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.providersetup.activities;
 
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -30,18 +30,27 @@ import org.jetbrains.annotations.NotNull;
 import org.json.JSONException;
 import org.json.JSONObject;
 
-import static se.leap.bitmaskclient.Constants.BROADCAST_PROVIDER_API_EVENT;
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
-import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
-import static se.leap.bitmaskclient.ProviderAPI.UPDATE_PROVIDER_DETAILS;
-import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.PENDING_SHOW_FAILED_DIALOG;
-import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.PENDING_SHOW_PROVIDER_DETAILS;
-import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.PROVIDER_NOT_SET;
-import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER;
-import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SHOWING_PROVIDER_DETAILS;
-import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SHOW_FAILED_DIALOG;
+import se.leap.bitmaskclient.base.FragmentManagerEnhanced;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.ProviderAPICommand;
+import se.leap.bitmaskclient.providersetup.ProviderDetailActivity;
+import se.leap.bitmaskclient.providersetup.ProviderApiSetupBroadcastReceiver;
+import se.leap.bitmaskclient.providersetup.ProviderManager;
+import se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog;
+import se.leap.bitmaskclient.providersetup.ProviderSetupInterface;
+
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_PROVIDER_API_EVENT;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_PROVIDER_DETAILS;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.PENDING_SHOW_FAILED_DIALOG;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.PENDING_SHOW_PROVIDER_DETAILS;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.PROVIDER_NOT_SET;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.SHOWING_PROVIDER_DETAILS;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.SHOW_FAILED_DIALOG;
 
 /**
  * Created by cyberta on 19.08.18.
diff --git a/app/src/main/java/se/leap/bitmaskclient/SignupActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SignupActivity.java
similarity index 94%
rename from app/src/main/java/se/leap/bitmaskclient/SignupActivity.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SignupActivity.java
index abd3d224992167af0de863b2b90bedb3885aa2d2..c02458458af398bc3e4606ca6e6df8f1e3aeb16f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/SignupActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SignupActivity.java
@@ -14,12 +14,13 @@
  * 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.providersetup.activities;
 
 import android.os.Bundle;
 import androidx.annotation.Nullable;
 
 import butterknife.OnClick;
+import se.leap.bitmaskclient.R;
 
 import static android.view.View.VISIBLE;
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/DnsResolver.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/DnsResolver.java
similarity index 84%
rename from app/src/main/java/se/leap/bitmaskclient/DnsResolver.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/DnsResolver.java
index 92f70492ff8a63b2029363cca9718f56b5e63d20..44de1e6d9d44f1c2dcc2478b3e56094666ff68f7 100644
--- a/app/src/main/java/se/leap/bitmaskclient/DnsResolver.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/DnsResolver.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup.connectivity;
 
 import org.jetbrains.annotations.NotNull;
 
@@ -8,7 +8,9 @@ import java.util.ArrayList;
 import java.util.List;
 
 import okhttp3.Dns;
-import se.leap.bitmaskclient.utils.IPAddress;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
+import se.leap.bitmaskclient.base.utils.IPAddress;
 
 class DnsResolver implements Dns {
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/OkHttpClientGenerator.java
similarity index 96%
rename from app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/OkHttpClientGenerator.java
index 576e76e054cc8f10cb460ddb886d8e6a817b66eb..2077a8b9b896a4ad4c1aa22982d2cce7aa4bcd65 100644
--- a/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/OkHttpClientGenerator.java
@@ -15,11 +15,11 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup.connectivity;
 
-import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.os.Build;
+
 import androidx.annotation.NonNull;
 
 import org.json.JSONException;
@@ -46,13 +46,13 @@ import okhttp3.OkHttpClient;
 import okhttp3.TlsVersion;
 
 import static android.text.TextUtils.isEmpty;
-import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
 import static se.leap.bitmaskclient.R.string.certificate_error;
 import static se.leap.bitmaskclient.R.string.error_io_exception_user_message;
 import static se.leap.bitmaskclient.R.string.error_no_such_algorithm_exception_user_message;
 import static se.leap.bitmaskclient.R.string.keyChainAccessError;
 import static se.leap.bitmaskclient.R.string.server_unreachable_message;
-import static se.leap.bitmaskclient.utils.ConfigHelper.getProviderFormattedString;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString;
 
 /**
  * Created by cyberta on 08.01.18.
diff --git a/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/TLSCompatSocketFactory.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/TLSCompatSocketFactory.java
index 326529648f1abc50e0f553bda7f7baa8624e20b2..5357fd749eff3c352581db08ca64b45563a7e9cb 100644
--- a/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/TLSCompatSocketFactory.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup.connectivity;
 
 import android.text.TextUtils;
 
@@ -22,7 +22,7 @@ import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
 import okhttp3.OkHttpClient;
-import se.leap.bitmaskclient.utils.ConfigHelper;
+import se.leap.bitmaskclient.base.utils.ConfigHelper;
 
 /**
  * Created by cyberta on 24.10.17.
diff --git a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/models/LeapSRPSession.java
similarity index 98%
rename from app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/models/LeapSRPSession.java
index d1f1ed2188989eba46c2cdb79dee54d67b3c7ea6..8e9d3e32a5ceba13c02e52c1d5dbb09e4a506edd 100644
--- a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/models/LeapSRPSession.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.providersetup.models;
 
 
 import org.jboss.security.srp.SRPParameters;
@@ -26,7 +26,7 @@ import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 import java.util.Arrays;
 
-import se.leap.bitmaskclient.utils.ConfigHelper;
+import se.leap.bitmaskclient.base.utils.ConfigHelper;
 
 /**
  * Implements all SRP algorithm logic.
@@ -330,11 +330,11 @@ public class LeapSRPSession {
         return valid;
     }
 
-    protected static void setToken(String token) {
+    public static void setToken(String token) {
         LeapSRPSession.token = token;
     }
 
-    protected static String getToken() {
+    public static String getToken() {
         return token;
     }
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/SrpCredentials.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/models/SrpCredentials.java
similarity index 88%
rename from app/src/main/java/se/leap/bitmaskclient/SrpCredentials.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/models/SrpCredentials.java
index c1815ac566a8379a93841c7cb343d678f9a56186..46a6262699f0dcd05aa55b6c3587d9dc882f4945 100644
--- a/app/src/main/java/se/leap/bitmaskclient/SrpCredentials.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/models/SrpCredentials.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup.models;
 
 import com.google.gson.Gson;
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/SrpRegistrationData.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/models/SrpRegistrationData.java
similarity index 94%
rename from app/src/main/java/se/leap/bitmaskclient/SrpRegistrationData.java
rename to app/src/main/java/se/leap/bitmaskclient/providersetup/models/SrpRegistrationData.java
index d4e0030827507aa0b84a9e9212c0deaf551355e1..31228edf026b9d8bb5fa8e451b0d8ef7d94bbac0 100644
--- a/app/src/main/java/se/leap/bitmaskclient/SrpRegistrationData.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/models/SrpRegistrationData.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup.models;
 
 import com.google.gson.Gson;
 
diff --git a/app/src/main/java/se/leap/bitmaskclient/tethering/TetheringStateManager.java b/app/src/main/java/se/leap/bitmaskclient/tethering/TetheringStateManager.java
index 44e9da6e911f1d7ca15da9daa1efcda47c131f09..d74175f5be3956abb60862968b8925137ce00172 100644
--- a/app/src/main/java/se/leap/bitmaskclient/tethering/TetheringStateManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/tethering/TetheringStateManager.java
@@ -18,7 +18,6 @@ package se.leap.bitmaskclient.tethering;
 
 import android.content.Context;
 import android.content.IntentFilter;
-import androidx.annotation.VisibleForTesting;
 
 import java.net.Inet4Address;
 import java.net.InterfaceAddress;
@@ -26,11 +25,11 @@ import java.net.NetworkInterface;
 import java.util.Enumeration;
 import java.util.List;
 
-import se.leap.bitmaskclient.utils.Cmd;
+import se.leap.bitmaskclient.base.utils.Cmd;
 
-import static se.leap.bitmaskclient.utils.PreferenceHelper.isBluetoothTetheringAllowed;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.isUsbTetheringAllowed;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.isWifiTetheringAllowed;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.isBluetoothTetheringAllowed;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.isUsbTetheringAllowed;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.isWifiTetheringAllowed;
 
 /**
  * This manager tries to figure out the current tethering states for Wifi, USB and Bluetooth
diff --git a/app/src/main/res/layout-xlarge-port/a_add_provider.xml b/app/src/main/res/layout-xlarge-port/a_add_provider.xml
index 2ec2f1b72101474cab77f20465e13b26b0f21f2c..9d1614aa3f632fe9d84b620c8eeddc948f66d3c7 100644
--- a/app/src/main/res/layout-xlarge-port/a_add_provider.xml
+++ b/app/src/main/res/layout-xlarge-port/a_add_provider.xml
@@ -5,7 +5,7 @@
     style="@style/BitmaskActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ProviderCredentialsBaseActivity">
+    tools:context=".providersetup.activities.ProviderCredentialsBaseActivity">
 
     <androidx.appcompat.widget.AppCompatImageView
         android:layout_width="match_parent"
diff --git a/app/src/main/res/layout-xlarge-port/a_custom_provider_setup.xml b/app/src/main/res/layout-xlarge-port/a_custom_provider_setup.xml
index 1f285968c46c02de24c1fa384652a8af9e97e26c..da813a2366a47c89a3d2aa0a68bab99ac2bd746a 100644
--- a/app/src/main/res/layout-xlarge-port/a_custom_provider_setup.xml
+++ b/app/src/main/res/layout-xlarge-port/a_custom_provider_setup.xml
@@ -6,7 +6,7 @@
     style="@style/BitmaskActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".CustomProviderSetupActivity">
+    tools:context=".providersetup.activities.CustomProviderSetupActivity">
 
     <androidx.appcompat.widget.AppCompatImageView
         android:layout_width="match_parent"
diff --git a/app/src/main/res/layout-xlarge-port/a_provider_credentials.xml b/app/src/main/res/layout-xlarge-port/a_provider_credentials.xml
index 73c2131c9be30801fc7a67d46dbf1402543a132c..75f6244abc1e96a70d077a7944af95a7411061dd 100644
--- a/app/src/main/res/layout-xlarge-port/a_provider_credentials.xml
+++ b/app/src/main/res/layout-xlarge-port/a_provider_credentials.xml
@@ -5,7 +5,7 @@
     style="@style/BitmaskActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ProviderCredentialsBaseActivity">
+    tools:context=".providersetup.activities.ProviderCredentialsBaseActivity">
 
     <androidx.appcompat.widget.AppCompatImageView
         android:layout_width="match_parent"
diff --git a/app/src/main/res/layout-xlarge-port/a_provider_detail.xml b/app/src/main/res/layout-xlarge-port/a_provider_detail.xml
index cb2045c9ff40e55a727878b4e6c3d7060d8cb5f2..7d1e8444bb88d2845d2a134e7f6023c4c501a0d4 100644
--- a/app/src/main/res/layout-xlarge-port/a_provider_detail.xml
+++ b/app/src/main/res/layout-xlarge-port/a_provider_detail.xml
@@ -5,7 +5,7 @@
     android:id="@+id/provider_list_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ProviderDetailActivity"
+    tools:context=".providersetup.ProviderDetailActivity"
     style="@style/BitmaskActivity">
 
     <androidx.appcompat.widget.AppCompatImageView
diff --git a/app/src/main/res/layout-xlarge-port/a_provider_list.xml b/app/src/main/res/layout-xlarge-port/a_provider_list.xml
index 94829b427c907430d73aba686689cb52e86024ab..87ca64275c681e6b7c26c3d593fe95aea14066e5 100644
--- a/app/src/main/res/layout-xlarge-port/a_provider_list.xml
+++ b/app/src/main/res/layout-xlarge-port/a_provider_list.xml
@@ -6,7 +6,7 @@
     style="@style/BitmaskActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ProviderListActivity">
+    tools:context=".providersetup.ProviderListActivity">
 
     <androidx.appcompat.widget.AppCompatImageView
         android:layout_width="match_parent"
diff --git a/app/src/main/res/layout-xlarge/a_add_provider.xml b/app/src/main/res/layout-xlarge/a_add_provider.xml
index 8cfd43c5ab423c84aca4c80669f77f3077e60491..e4ebdadfe3effbf2d95223f0daf90bcb4d7328a1 100644
--- a/app/src/main/res/layout-xlarge/a_add_provider.xml
+++ b/app/src/main/res/layout-xlarge/a_add_provider.xml
@@ -5,7 +5,7 @@
     style="@style/BitmaskActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ProviderCredentialsBaseActivity">
+    tools:context=".providersetup.activities.ProviderCredentialsBaseActivity">
 
     <androidx.appcompat.widget.AppCompatImageView
         android:layout_width="match_parent"
diff --git a/app/src/main/res/layout-xlarge/a_custom_provider_setup.xml b/app/src/main/res/layout-xlarge/a_custom_provider_setup.xml
index 7c9a17981a992a658c8aa031381759e300f9a6d2..23bf7d4061cb8ff6780e2d9a1ab21cfd244d9544 100644
--- a/app/src/main/res/layout-xlarge/a_custom_provider_setup.xml
+++ b/app/src/main/res/layout-xlarge/a_custom_provider_setup.xml
@@ -6,7 +6,7 @@
     style="@style/BitmaskActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".CustomProviderSetupActivity">
+    tools:context=".providersetup.activities.CustomProviderSetupActivity">
 
     <androidx.appcompat.widget.AppCompatImageView
         android:layout_width="match_parent"
diff --git a/app/src/main/res/layout-xlarge/a_provider_credentials.xml b/app/src/main/res/layout-xlarge/a_provider_credentials.xml
index 2cf9e16a2056f3666eb1efa40d66fe2318b7ec0e..c5b35fdce2875e8397642fca41b4660db9d3ad1a 100644
--- a/app/src/main/res/layout-xlarge/a_provider_credentials.xml
+++ b/app/src/main/res/layout-xlarge/a_provider_credentials.xml
@@ -5,7 +5,7 @@
     style="@style/BitmaskActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ProviderCredentialsBaseActivity">
+    tools:context=".providersetup.activities.ProviderCredentialsBaseActivity">
 
     <androidx.appcompat.widget.AppCompatImageView
         android:layout_width="match_parent"
diff --git a/app/src/main/res/layout-xlarge/a_provider_detail.xml b/app/src/main/res/layout-xlarge/a_provider_detail.xml
index bead7d924016937ad0a3911295a0e8063420bda8..59e9c18d6d235f7112e0d9ef8e619d650a27d324 100644
--- a/app/src/main/res/layout-xlarge/a_provider_detail.xml
+++ b/app/src/main/res/layout-xlarge/a_provider_detail.xml
@@ -5,7 +5,7 @@
     android:id="@+id/provider_list_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ProviderDetailActivity"
+    tools:context=".providersetup.ProviderDetailActivity"
     style="@style/BitmaskActivity">
 
     <androidx.appcompat.widget.AppCompatImageView
diff --git a/app/src/main/res/layout-xlarge/a_provider_list.xml b/app/src/main/res/layout-xlarge/a_provider_list.xml
index 58d75246abe7830dc6c987879ab8ba1a85607866..6504db1005a014d2377c6ec0136f203ff7069c9f 100644
--- a/app/src/main/res/layout-xlarge/a_provider_list.xml
+++ b/app/src/main/res/layout-xlarge/a_provider_list.xml
@@ -6,7 +6,7 @@
     style="@style/BitmaskActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ProviderListActivity">
+    tools:context=".providersetup.ProviderListActivity">
 
     <androidx.appcompat.widget.AppCompatImageView
         android:layout_width="match_parent"
diff --git a/app/src/main/res/layout-xlarge/f_about.xml b/app/src/main/res/layout-xlarge/f_about.xml
index 1d915da49e5f644c815c52c5ecc439bb40e1b8ca..704a7319be89b24b0f7764c7432a33bae21363c5 100644
--- a/app/src/main/res/layout-xlarge/f_about.xml
+++ b/app/src/main/res/layout-xlarge/f_about.xml
@@ -5,7 +5,7 @@
     android:layout_height="match_parent"
     android:orientation="vertical"
     android:layout_marginLeft="12sp"
-    tools:context=".MainActivity" >
+    tools:context=".base.MainActivity" >
 
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/app/src/main/res/layout-xlarge/f_eip.xml b/app/src/main/res/layout-xlarge/f_eip.xml
index fdaab8ca8f22f83d0934727f7a3b5f149fee34a0..d4a51b8dc378cfe6616302e90a7c0963a24f46a1 100644
--- a/app/src/main/res/layout-xlarge/f_eip.xml
+++ b/app/src/main/res/layout-xlarge/f_eip.xml
@@ -69,7 +69,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <se.leap.bitmaskclient.views.VpnStateImage
+    <se.leap.bitmaskclient.base.views.VpnStateImage
         android:id="@+id/vpn_state_image"
         android:layout_width="0dp"
         android:layout_height="0dp"
diff --git a/app/src/main/res/layout/a_add_provider.xml b/app/src/main/res/layout/a_add_provider.xml
index eab1693e9b07ebb312c25038b734a9da63d4e6c5..c78db432643b89e9ac2a8967e2a6898be936bb57 100644
--- a/app/src/main/res/layout/a_add_provider.xml
+++ b/app/src/main/res/layout/a_add_provider.xml
@@ -6,7 +6,7 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:padding="@dimen/stdpadding"
-    tools:context=".AddProviderActivity">
+    tools:context=".providersetup.AddProviderActivity">
 
     <LinearLayout
         android:id="@+id/content"
@@ -18,7 +18,7 @@
         android:orientation="vertical">
 
         <!-- the header contains the mask-->
-        <se.leap.bitmaskclient.views.ProviderHeaderView
+        <se.leap.bitmaskclient.base.views.ProviderHeaderView
             android:id="@+id/header"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"/>
diff --git a/app/src/main/res/layout/a_add_provider_tablet_scrollview.xml b/app/src/main/res/layout/a_add_provider_tablet_scrollview.xml
index 31c8d07cd1469c2687e64251ca73ddd601148e72..4debbf9f81d55c64669604d152133abf7d1bf267 100644
--- a/app/src/main/res/layout/a_add_provider_tablet_scrollview.xml
+++ b/app/src/main/res/layout/a_add_provider_tablet_scrollview.xml
@@ -23,7 +23,7 @@
         android:layout_height="wrap_content"
         android:orientation="vertical">
 
-        <se.leap.bitmaskclient.views.ProviderHeaderView
+        <se.leap.bitmaskclient.base.views.ProviderHeaderView
             android:id="@+id/header"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"/>
diff --git a/app/src/main/res/layout/a_custom_provider_setup.xml b/app/src/main/res/layout/a_custom_provider_setup.xml
index 34c59259ad3516f3f744c381b66ba25cdcf72b86..782537d9e264e491c57b13612e5373eea44ec229 100644
--- a/app/src/main/res/layout/a_custom_provider_setup.xml
+++ b/app/src/main/res/layout/a_custom_provider_setup.xml
@@ -4,7 +4,7 @@
     android:id="@+id/custom_provider_setup_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".CustomProviderSetupActivity"
+    tools:context=".providersetup.activities.CustomProviderSetupActivity"
     android:padding="@dimen/stdpadding"
     style="@style/BitmaskActivity" >
 
@@ -15,7 +15,7 @@
         android:layout_height="0dp"
         android:layout_width="0dp"
         android:id="@id/content">
-        <se.leap.bitmaskclient.views.ProviderHeaderView
+        <se.leap.bitmaskclient.base.views.ProviderHeaderView
             android:id="@+id/header"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/a_custom_provider_setup_tablet_linear_layout.xml b/app/src/main/res/layout/a_custom_provider_setup_tablet_linear_layout.xml
index 9fb670929ec30daa47dd12bce70df79c225416fe..4879c76f08124f918b4e074fa1f5bbe2f8244c43 100644
--- a/app/src/main/res/layout/a_custom_provider_setup_tablet_linear_layout.xml
+++ b/app/src/main/res/layout/a_custom_provider_setup_tablet_linear_layout.xml
@@ -18,7 +18,7 @@
         android:layout_height="0dp"
         android:layout_width="0dp"
         android:id="@id/content">
-        <se.leap.bitmaskclient.views.ProviderHeaderView
+        <se.leap.bitmaskclient.base.views.ProviderHeaderView
             android:id="@+id/header"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/a_main.xml b/app/src/main/res/layout/a_main.xml
index 1977be74822371a861edaa4761941498bbb75ec7..4e921a9cf79a6a870c7bbde888962cd6649a7d8d 100644
--- a/app/src/main/res/layout/a_main.xml
+++ b/app/src/main/res/layout/a_main.xml
@@ -5,7 +5,7 @@
     android:id="@+id/drawer_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context="se.leap.bitmaskclient.MainActivity">
+    tools:context="se.leap.bitmaskclient.base.MainActivity">
 
 
     <!-- As the main content view, the view below consumes the entire
@@ -34,7 +34,7 @@
          the container. -->
     <fragment
         android:id="@+id/navigation_drawer"
-        android:name="se.leap.bitmaskclient.drawer.NavigationDrawerFragment"
+        android:name="se.leap.bitmaskclient.base.drawer.NavigationDrawerFragment"
         android:layout_width="@dimen/navigation_drawer_width"
         android:layout_height="match_parent"
         android:layout_gravity="start"
diff --git a/app/src/main/res/layout/a_provider_credentials.xml b/app/src/main/res/layout/a_provider_credentials.xml
index 93f44208dba371e41028875e9445de5f3de92be1..b5dfa08874212f7171d1476d00f2e18e9a5e60a4 100644
--- a/app/src/main/res/layout/a_provider_credentials.xml
+++ b/app/src/main/res/layout/a_provider_credentials.xml
@@ -16,7 +16,7 @@
         android:layout_height="match_parent"
         >
 
-        <se.leap.bitmaskclient.views.ProviderHeaderView
+        <se.leap.bitmaskclient.base.views.ProviderHeaderView
             android:id="@+id/header"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
diff --git a/app/src/main/res/layout/a_provider_credentials_tablet_linear_layout.xml b/app/src/main/res/layout/a_provider_credentials_tablet_linear_layout.xml
index bf022d5169f40e7d6cd0cbd83ae841ea201b8633..ea0b6dd4f368f22e380a9a632e12d8c6a87a4eae 100644
--- a/app/src/main/res/layout/a_provider_credentials_tablet_linear_layout.xml
+++ b/app/src/main/res/layout/a_provider_credentials_tablet_linear_layout.xml
@@ -23,7 +23,7 @@
         android:id="@+id/content"
         android:orientation="vertical">
 
-        <se.leap.bitmaskclient.views.ProviderHeaderView
+        <se.leap.bitmaskclient.base.views.ProviderHeaderView
             android:id="@+id/header"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"/>
diff --git a/app/src/main/res/layout/a_provider_detail.xml b/app/src/main/res/layout/a_provider_detail.xml
index 840d60df014dcb28dd11dda1937b396bb4d3f15e..bdc17ee91c2309b1cd762fb1bdb70a3dbd1c02c7 100644
--- a/app/src/main/res/layout/a_provider_detail.xml
+++ b/app/src/main/res/layout/a_provider_detail.xml
@@ -15,7 +15,7 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
-        <se.leap.bitmaskclient.views.ProviderHeaderView
+        <se.leap.bitmaskclient.base.views.ProviderHeaderView
             android:id="@+id/header"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
diff --git a/app/src/main/res/layout/a_provider_detail_tablet_linear_layout.xml b/app/src/main/res/layout/a_provider_detail_tablet_linear_layout.xml
index 51c5ab0fa55458a7080b8f7cb6434dca7c85ebad..0c7e02d1c2bf69ed803f62e227f428f609743df6 100644
--- a/app/src/main/res/layout/a_provider_detail_tablet_linear_layout.xml
+++ b/app/src/main/res/layout/a_provider_detail_tablet_linear_layout.xml
@@ -23,7 +23,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
 
-        <se.leap.bitmaskclient.views.ProviderHeaderView
+        <se.leap.bitmaskclient.base.views.ProviderHeaderView
             android:id="@+id/header"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"/>
diff --git a/app/src/main/res/layout/a_provider_list.xml b/app/src/main/res/layout/a_provider_list.xml
index 2e2573eb58b3863f46eec2c58c12444ddeceab37..5d7efae748fe3d08bda5a5070e1ae30a0890decc 100644
--- a/app/src/main/res/layout/a_provider_list.xml
+++ b/app/src/main/res/layout/a_provider_list.xml
@@ -3,7 +3,7 @@
     android:id="@+id/provider_list_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ProviderListActivity"
+    tools:context=".providersetup.ProviderListActivity"
     android:padding="@dimen/stdpadding"
     style="@style/BitmaskActivity" >
 
@@ -15,7 +15,7 @@
         android:layout_height="match_parent"
         android:orientation="vertical">
 
-        <se.leap.bitmaskclient.views.ProviderHeaderView
+        <se.leap.bitmaskclient.base.views.ProviderHeaderView
             android:id="@+id/header"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
diff --git a/app/src/main/res/layout/a_provider_list_tablet_linear_layout.xml b/app/src/main/res/layout/a_provider_list_tablet_linear_layout.xml
index 107f25fba592dc7d27f49bc309866a874fba6c83..487edd1d350d2f0da98c8280d72e34a956da7deb 100644
--- a/app/src/main/res/layout/a_provider_list_tablet_linear_layout.xml
+++ b/app/src/main/res/layout/a_provider_list_tablet_linear_layout.xml
@@ -22,7 +22,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
 
-        <se.leap.bitmaskclient.views.ProviderHeaderView
+        <se.leap.bitmaskclient.base.views.ProviderHeaderView
             android:id="@+id/header"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"/>
diff --git a/app/src/main/res/layout/d_checkbox_confirm.xml b/app/src/main/res/layout/d_checkbox_confirm.xml
index b2b61eca85217591ec87aca1a4c8cb1940e0cd8c..f8aace6ec3b60e70dce6414fe1d1589ef5dfd61e 100644
--- a/app/src/main/res/layout/d_checkbox_confirm.xml
+++ b/app/src/main/res/layout/d_checkbox_confirm.xml
@@ -24,7 +24,7 @@
             android:textStyle="bold"
             />
 
-        <se.leap.bitmaskclient.views.IconTextView
+        <se.leap.bitmaskclient.base.views.IconTextView
             android:id="@+id/user_message"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/f_about.xml b/app/src/main/res/layout/f_about.xml
index 2205305433cbb75a8a41fb8a934963f46f095927..ec7369ef664ec13820ca21324c553773f8af330e 100644
--- a/app/src/main/res/layout/f_about.xml
+++ b/app/src/main/res/layout/f_about.xml
@@ -5,7 +5,7 @@
     android:layout_height="match_parent"
     android:orientation="vertical"
     android:layout_marginLeft="8sp"
-    tools:context=".MainActivity" >
+    tools:context=".base.MainActivity" >
 
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/f_drawer_main.xml b/app/src/main/res/layout/f_drawer_main.xml
index 5a0977da8e671b11fcd2d53890e8f2f5b329b712..be60e6204381737b1bf64c7d209e0212b20d87f5 100644
--- a/app/src/main/res/layout/f_drawer_main.xml
+++ b/app/src/main/res/layout/f_drawer_main.xml
@@ -4,7 +4,7 @@
     android:layout_height="match_parent"
     android:layout_width="match_parent"
     android:background="@color/colorBackground"
-    tools:context="se.leap.bitmaskclient.drawer.NavigationDrawerFragment"
+    tools:context=".base.drawer.NavigationDrawerFragment"
     android:clickable="true"
     android:focusable="true"
     android:fillViewport="true"
@@ -37,13 +37,13 @@
                 app:srcCompat="@drawable/drawer_logo" />
         </FrameLayout>
 
-        <se.leap.bitmaskclient.views.IconTextEntry
+        <se.leap.bitmaskclient.base.views.IconTextEntry
             android:id="@+id/account"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             />
 
-        <se.leap.bitmaskclient.views.IconTextEntry
+        <se.leap.bitmaskclient.base.views.IconTextEntry
             android:id="@+id/switch_provider"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
@@ -60,7 +60,7 @@
             android:background="@color/black800_high_transparent"
             />
 
-        <se.leap.bitmaskclient.views.IconSwitchEntry
+        <se.leap.bitmaskclient.base.views.IconSwitchEntry
             android:id="@+id/battery_switch"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -69,7 +69,7 @@
             app:icon="@drawable/ic_battery_36"
             />
 
-        <se.leap.bitmaskclient.views.IconSwitchEntry
+        <se.leap.bitmaskclient.base.views.IconSwitchEntry
             android:id="@+id/bridges_switch"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -79,7 +79,7 @@
             android:visibility="gone"
             />
 
-        <se.leap.bitmaskclient.views.IconTextEntry
+        <se.leap.bitmaskclient.base.views.IconTextEntry
             android:id="@+id/always_on_vpn"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -89,7 +89,7 @@
             android:visibility="gone"
             />
 
-        <se.leap.bitmaskclient.views.IconTextEntry
+        <se.leap.bitmaskclient.base.views.IconTextEntry
             android:id="@+id/exclude_apps"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -110,7 +110,7 @@
             android:background="@color/black800_high_transparent"
             />
 
-        <se.leap.bitmaskclient.views.IconSwitchEntry
+        <se.leap.bitmaskclient.base.views.IconSwitchEntry
             android:id="@+id/enableIPv6Firewall"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -121,7 +121,7 @@
             tools:visibility="visible"
             />
 
-        <se.leap.bitmaskclient.views.IconTextEntry
+        <se.leap.bitmaskclient.base.views.IconTextEntry
             android:id="@+id/tethering"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -141,7 +141,7 @@
             tools:visibility="visible"
             />
 
-        <se.leap.bitmaskclient.views.IconTextEntry
+        <se.leap.bitmaskclient.base.views.IconTextEntry
             android:id="@+id/donate"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -150,7 +150,7 @@
             android:visibility="gone"
             />
 
-        <se.leap.bitmaskclient.views.IconTextEntry
+        <se.leap.bitmaskclient.base.views.IconTextEntry
             android:id="@+id/log"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -158,7 +158,7 @@
             app:icon="@drawable/ic_log_36"
             />
 
-        <se.leap.bitmaskclient.views.IconTextEntry
+        <se.leap.bitmaskclient.base.views.IconTextEntry
             android:id="@+id/about"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/f_eip.xml b/app/src/main/res/layout/f_eip.xml
index 01feb0cd265c4ea3391cac64ffaf9ae542474cac..3309eb5d8753ed65c8df40fe198ebe66b7004115 100644
--- a/app/src/main/res/layout/f_eip.xml
+++ b/app/src/main/res/layout/f_eip.xml
@@ -70,7 +70,7 @@
         app:layout_constraintTop_toTopOf="parent" />
 
 
-    <se.leap.bitmaskclient.views.VpnStateImage
+    <se.leap.bitmaskclient.base.views.VpnStateImage
         android:id="@+id/vpn_state_image"
         android:layout_width="0dp"
         android:layout_height="0dp"
diff --git a/app/src/main/res/values/untranslatable.xml b/app/src/main/res/values/untranslatable.xml
index 0d680b9611cfa07a1f3706c473b913aac7ffab1b..9c6afadd59b32f2e8fbebc6ce76deaea8e15512b 100644
--- a/app/src/main/res/values/untranslatable.xml
+++ b/app/src/main/res/values/untranslatable.xml
@@ -44,4 +44,5 @@
     <string name="circleImageView" translatable="false">CircleImageView</string>
     <string name="copyright_circleImageView" translatable="false">Copyright 2014 - 2020 Henning Dodenhof. Licensed under the Apache License, Version 2.0 </string>
 
-</resources>
+
+</resources>
\ No newline at end of file
diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderDetailActivity.java b/app/src/production/java/se/leap/bitmaskclient/ProviderDetailActivity.java
deleted file mode 100644
index e1815689de65b164ee4c968fbf1bc2b7f51cce1e..0000000000000000000000000000000000000000
--- a/app/src/production/java/se/leap/bitmaskclient/ProviderDetailActivity.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package se.leap.bitmaskclient;
-
-public class ProviderDetailActivity extends AbstractProviderDetailActivity {
-}
diff --git a/app/src/production/java/se/leap/bitmaskclient/AddProviderActivity.java b/app/src/production/java/se/leap/bitmaskclient/providersetup/AddProviderActivity.java
similarity index 82%
rename from app/src/production/java/se/leap/bitmaskclient/AddProviderActivity.java
rename to app/src/production/java/se/leap/bitmaskclient/providersetup/AddProviderActivity.java
index ed076d3fdab6f1a534d441f24f056d15de954e6f..d05c76f08bd2f174cb1b62c3cfe5b33a0b8dc04c 100644
--- a/app/src/production/java/se/leap/bitmaskclient/AddProviderActivity.java
+++ b/app/src/production/java/se/leap/bitmaskclient/providersetup/AddProviderActivity.java
@@ -1,10 +1,12 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import android.os.Bundle;
 import android.view.View;
 import android.widget.Button;
 
 import butterknife.InjectView;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.providersetup.activities.AddProviderBaseActivity;
 
 public class AddProviderActivity extends AddProviderBaseActivity {
 
diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderApiManager.java
similarity index 93%
rename from app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java
rename to app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderApiManager.java
index 4a4e7b2204bfc8f793b19cf849639a8097fcf3c7..592db08531a703aaed158990f21fb6b0d3d021e9 100644
--- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java
+++ b/app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderApiManager.java
@@ -15,7 +15,7 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import android.content.SharedPreferences;
 import android.content.res.Resources;
@@ -33,23 +33,26 @@ import java.util.List;
 
 import de.blinkt.openvpn.core.VpnStatus;
 import okhttp3.OkHttpClient;
+import se.leap.bitmaskclient.R;
 import se.leap.bitmaskclient.eip.EIP;
-import se.leap.bitmaskclient.utils.ConfigHelper;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator;
+import se.leap.bitmaskclient.base.utils.ConfigHelper;
 
 import static android.text.TextUtils.isEmpty;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
-import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING;
-import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON;
 import static se.leap.bitmaskclient.R.string.downloading_vpn_certificate_failed;
 import static se.leap.bitmaskclient.R.string.error_io_exception_user_message;
 import static se.leap.bitmaskclient.R.string.malformed_url;
 import static se.leap.bitmaskclient.R.string.setup_error_text;
 import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_cert;
 import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_details;
-import static se.leap.bitmaskclient.utils.ConfigHelper.getProviderFormattedString;
+import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString;
 
 /**
  * Implements the logic of the provider api http requests. The methods of this class need to be called from
@@ -68,7 +71,7 @@ public class ProviderApiManager extends ProviderApiManagerBase {
     /**
      * Only used in insecure flavor.
      */
-    static boolean lastDangerOn() {
+    public static boolean lastDangerOn() {
         return false;
     }
 
diff --git a/app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderDetailActivity.java b/app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderDetailActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec932394ad11a755f7030abc09957e0e635a952a
--- /dev/null
+++ b/app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderDetailActivity.java
@@ -0,0 +1,6 @@
+package se.leap.bitmaskclient.providersetup;
+
+import se.leap.bitmaskclient.providersetup.activities.AbstractProviderDetailActivity;
+
+public class ProviderDetailActivity extends AbstractProviderDetailActivity {
+}
diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java b/app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderListActivity.java
similarity index 78%
rename from app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java
rename to app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderListActivity.java
index cf3277910c1628a74af5265f70bc50f00a25d879..6a1eaf95538d8abb8b24d64d9bd9b95dc187e4fb 100644
--- a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java
+++ b/app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderListActivity.java
@@ -14,12 +14,16 @@
  * 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.providersetup;
 
 import androidx.annotation.NonNull;
 
-import static se.leap.bitmaskclient.ProviderAPI.SET_UP_PROVIDER;
-import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.ProviderAPICommand;
+import se.leap.bitmaskclient.providersetup.activities.ProviderListBaseActivity;
+
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.SET_UP_PROVIDER;
+import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER;
 
 /**
  * Activity that builds and shows the list of known available providers.
diff --git a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java b/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java
index c741faf2e312ee8cf67a97266ad806671dea2b47..729c75eddc131315fe9db4b5f4059180b1033a92 100644
--- a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java
+++ b/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java
@@ -24,9 +24,8 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.net.URL;
 
-import se.leap.bitmaskclient.Provider;
+import se.leap.bitmaskclient.base.models.Provider;
 
 /**
  * Created by cyberta on 08.10.17.
diff --git a/app/src/test/java/se/leap/bitmaskclient/DefaultedURLTest.java b/app/src/test/java/se/leap/bitmaskclient/base/models/DefaultedURLTest.java
similarity index 88%
rename from app/src/test/java/se/leap/bitmaskclient/DefaultedURLTest.java
rename to app/src/test/java/se/leap/bitmaskclient/base/models/DefaultedURLTest.java
index cbf4762186317ef5d847e61fbcfd3c58f32303bb..551206d9991a3149617aaacec2a70ad1745f6987 100644
--- a/app/src/test/java/se/leap/bitmaskclient/DefaultedURLTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/base/models/DefaultedURLTest.java
@@ -1,10 +1,12 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.base.models;
 
 import org.junit.Test;
 
 import java.net.MalformedURLException;
 import java.net.URL;
 
+import se.leap.bitmaskclient.base.models.DefaultedURL;
+
 import static org.junit.Assert.*;
 
 /**
diff --git a/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java b/app/src/test/java/se/leap/bitmaskclient/base/models/ProviderTest.java
similarity index 96%
rename from app/src/test/java/se/leap/bitmaskclient/ProviderTest.java
rename to app/src/test/java/se/leap/bitmaskclient/base/models/ProviderTest.java
index 8a74e5dea5fd25be7c8938f85e695267052a09f4..aaf3f255fc8a242adb5cb557e8fae8619df495ab 100644
--- a/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/base/models/ProviderTest.java
@@ -1,10 +1,11 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.base.models;
 
 import org.junit.Test;
 
 import java.util.HashSet;
 import java.util.Set;
 
+import se.leap.bitmaskclient.base.models.Provider;
 import se.leap.bitmaskclient.testutils.TestSetupHelper;
 
 import static junit.framework.Assert.assertFalse;
diff --git a/app/src/test/java/se/leap/bitmaskclient/PreferenceHelperTest.java b/app/src/test/java/se/leap/bitmaskclient/base/utils/PreferenceHelperTest.java
similarity index 81%
rename from app/src/test/java/se/leap/bitmaskclient/PreferenceHelperTest.java
rename to app/src/test/java/se/leap/bitmaskclient/base/utils/PreferenceHelperTest.java
index edac3480329941deb9623f2714c47823571b97e1..955ddc44c5ddb7ef5c18ebd036178da214db883f 100644
--- a/app/src/test/java/se/leap/bitmaskclient/PreferenceHelperTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/base/utils/PreferenceHelperTest.java
@@ -1,19 +1,20 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.base.utils;
 
 import android.content.SharedPreferences;
 
 import org.junit.Before;
 import org.junit.Test;
 
+import se.leap.bitmaskclient.base.models.Provider;
 import se.leap.bitmaskclient.testutils.MockSharedPreferences;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_EIP_DEFINITION;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
 import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.getSavedProviderFromSharedPreferences;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getSavedProviderFromSharedPreferences;
 
 /**
  * Created by cyberta on 17.01.18.
diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java
index 8ba7f5fc37476bea25ad7881910bb034b85cc594..1e15c5abd08bd2cbd1b0d726bd659ce35ccf1400 100644
--- a/app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java
@@ -3,18 +3,14 @@ package se.leap.bitmaskclient.eip;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatchers;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
 import de.blinkt.openvpn.VpnProfile;
 import de.blinkt.openvpn.core.ConnectionStatus;
 import de.blinkt.openvpn.core.VpnStatus;
-import de.blinkt.openvpn.core.connection.Connection;
 import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.testutils.MockHelper;
-import se.leap.bitmaskclient.testutils.TestSetupHelper;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
 
 import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_AUTH_FAILED;
 import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED;
@@ -26,7 +22,6 @@ import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INP
 import static de.blinkt.openvpn.core.ConnectionStatus.UNKNOWN_LEVEL;
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN;
 import static junit.framework.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.powermock.api.mockito.PowerMockito.doNothing;
 import static org.powermock.api.mockito.PowerMockito.mockStatic;
 import static org.powermock.api.mockito.PowerMockito.when;
diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java
index 5d5a959b993097509e62943171c19e8640bb9c5e..8c074dd878baac4ecb28265010a152d04f0914c8 100644
--- a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java
@@ -18,15 +18,15 @@ import java.io.IOException;
 import java.util.ArrayList;
 
 import de.blinkt.openvpn.core.ConfigParser;
-import se.leap.bitmaskclient.Provider;
-import se.leap.bitmaskclient.utils.ConfigHelper;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.utils.ConfigHelper;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 import static org.powermock.api.mockito.PowerMockito.mockStatic;
 import static org.powermock.api.mockito.PowerMockito.when;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
 import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString;
 
 /**
diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java
index bfe96d2c8f0c516fc81d645ae45b11e2f1d3b26b..01e2732078cfbb3cdb83d8b22299638d9b1d7c8a 100644
--- a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java
@@ -18,14 +18,13 @@ import java.io.IOException;
 
 import de.blinkt.openvpn.VpnProfile;
 import de.blinkt.openvpn.core.ConfigParser;
-import de.blinkt.openvpn.core.connection.Connection;
-import se.leap.bitmaskclient.Provider;
-import se.leap.bitmaskclient.ProviderObservable;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
 import se.leap.bitmaskclient.testutils.MockHelper;
 import se.leap.bitmaskclient.testutils.MockSharedPreferences;
 import se.leap.bitmaskclient.testutils.TestSetupHelper;
-import se.leap.bitmaskclient.utils.ConfigHelper;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.utils.ConfigHelper;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
 
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN;
@@ -38,11 +37,11 @@ import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.powermock.api.mockito.PowerMockito.mockStatic;
-import static se.leap.bitmaskclient.Constants.GATEWAYS;
-import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.Provider.CA_CERT;
+import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_EIP_DEFINITION;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.models.Provider.CA_CERT;
 import static se.leap.bitmaskclient.testutils.TestSetupHelper.getProvider;
 
 /**
diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java
index efa6f78c9b70e9f51f98677c99ffa37232f5ac7b..38449c20aa69fd7b18af7c061e0aebecb9e54064 100644
--- a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java
@@ -40,25 +40,24 @@ import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateEncodingException;
 
 import se.leap.bitmaskclient.BuildConfig;
-import se.leap.bitmaskclient.Provider;
-import se.leap.bitmaskclient.ProviderAPI;
-import se.leap.bitmaskclient.ProviderApiConnector;
-import se.leap.bitmaskclient.ProviderApiManager;
-import se.leap.bitmaskclient.ProviderApiManagerBase;
-import se.leap.bitmaskclient.testutils.BackendMockResponses.GeoIpServiceIsDownBackendResponse;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.ProviderAPI;
+import se.leap.bitmaskclient.providersetup.ProviderApiConnector;
+import se.leap.bitmaskclient.providersetup.ProviderApiManager;
+import se.leap.bitmaskclient.providersetup.ProviderApiManagerBase;
 import se.leap.bitmaskclient.testutils.MockSharedPreferences;
-import se.leap.bitmaskclient.utils.ConfigHelper;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
-
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;
-import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON;
-import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
-import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON;
-import static se.leap.bitmaskclient.ProviderAPI.PARAMETERS;
-import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_NOK;
-import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_OK;
+import se.leap.bitmaskclient.base.utils.ConfigHelper;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
+
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.PARAMETERS;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_NOK;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_OK;
 import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_FETCH_EIP_SERVICE_CERTIFICATE_INVALID;
 import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_MICONFIGURED_PROVIDER;
 import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_UPDATED_CERTIFICATE;
diff --git a/app/src/test/java/se/leap/bitmaskclient/ProviderManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/providersetup/ProviderManagerTest.java
similarity index 96%
rename from app/src/test/java/se/leap/bitmaskclient/ProviderManagerTest.java
rename to app/src/test/java/se/leap/bitmaskclient/providersetup/ProviderManagerTest.java
index 1914f989c1004489e6b096e92bfde1e0b3711843..c48f520e7dac4015c2e0dac7bcbdda48ff9b4fd0 100644
--- a/app/src/test/java/se/leap/bitmaskclient/ProviderManagerTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/providersetup/ProviderManagerTest.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.providersetup;
 
 import android.content.res.AssetManager;
 
@@ -16,9 +16,11 @@ import java.io.File;
 import java.io.InputStream;
 import java.util.ArrayList;
 
-import se.leap.bitmaskclient.utils.ConfigHelper;
-import se.leap.bitmaskclient.utils.FileHelper;
-import se.leap.bitmaskclient.utils.InputStreamHelper;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.utils.ConfigHelper;
+import se.leap.bitmaskclient.base.utils.FileHelper;
+import se.leap.bitmaskclient.base.utils.InputStreamHelper;
+import se.leap.bitmaskclient.providersetup.ProviderManager;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BaseBackendResponse.java b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BaseBackendResponse.java
index 9822401941b8cccb456fcea4da75097d15493bd2..9a538d3c5ec0d12f6af4db49aac9ea16d3953dc0 100644
--- a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BaseBackendResponse.java
+++ b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BaseBackendResponse.java
@@ -25,7 +25,7 @@ import org.mockito.stubbing.Answer;
 import java.io.IOException;
 
 import okhttp3.OkHttpClient;
-import se.leap.bitmaskclient.ProviderApiConnector;
+import se.leap.bitmaskclient.providersetup.ProviderApiConnector;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java
index d3d073085d8769870997fadb9bba30cdde903c91..d4b7c5d1b03bfae5842a30ed1e29762c7a3f73d2 100644
--- a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java
+++ b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java
@@ -34,16 +34,16 @@ import java.util.Map;
 import java.util.Set;
 
 import okhttp3.OkHttpClient;
-import se.leap.bitmaskclient.OkHttpClientGenerator;
-import se.leap.bitmaskclient.Provider;
-import se.leap.bitmaskclient.ProviderObservable;
+import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
 import se.leap.bitmaskclient.R;
 import se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider;
 import se.leap.bitmaskclient.testutils.matchers.BundleMatcher;
-import se.leap.bitmaskclient.utils.ConfigHelper;
-import se.leap.bitmaskclient.utils.FileHelper;
-import se.leap.bitmaskclient.utils.InputStreamHelper;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.utils.ConfigHelper;
+import se.leap.bitmaskclient.base.utils.FileHelper;
+import se.leap.bitmaskclient.base.utils.InputStreamHelper;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
@@ -57,11 +57,11 @@ import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.powermock.api.mockito.PowerMockito.mockStatic;
-import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
-import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.utils.FileHelper.createFile;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.getEipDefinitionFromPreferences;
-import static se.leap.bitmaskclient.utils.PreferenceHelper.getFromPersistedProvider;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.utils.FileHelper.createFile;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getEipDefinitionFromPreferences;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getFromPersistedProvider;
 
 /**
  * Created by cyberta on 29.01.18.
diff --git a/app/src/test/java/se/leap/bitmaskclient/tethering/TetheringStateManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/tethering/TetheringStateManagerTest.java
index b3ab75ba585a7529a128711547623b11e301501d..509805d468125ffa36b1020564c1c30361c2bac1 100644
--- a/app/src/test/java/se/leap/bitmaskclient/tethering/TetheringStateManagerTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/tethering/TetheringStateManagerTest.java
@@ -36,7 +36,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 
-import se.leap.bitmaskclient.utils.Cmd;
+import se.leap.bitmaskclient.base.utils.Cmd;
 
 import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assert.assertEquals;