Refactor transport components to eliminate need to initialize and reset transport
diff --git a/app/src/main/java/com/stevesoltys/backup/activity/MainActivityController.java b/app/src/main/java/com/stevesoltys/backup/activity/MainActivityController.java
index f569d37..d9e13ff 100644
--- a/app/src/main/java/com/stevesoltys/backup/activity/MainActivityController.java
+++ b/app/src/main/java/com/stevesoltys/backup/activity/MainActivityController.java
@@ -8,7 +8,6 @@
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.net.Uri;
-import android.util.Log;
 import android.widget.Toast;
 
 import com.stevesoltys.backup.activity.backup.CreateBackupActivity;
@@ -16,11 +15,6 @@
 import com.stevesoltys.backup.service.backup.BackupJobService;
 import com.stevesoltys.backup.transport.ConfigurableBackupTransportService;
 
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-
 import static android.app.job.JobInfo.NETWORK_TYPE_UNMETERED;
 import static android.content.Intent.ACTION_OPEN_DOCUMENT;
 import static android.content.Intent.ACTION_OPEN_DOCUMENT_TREE;
@@ -28,9 +22,6 @@
 import static android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
 import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
 import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
-import static android.provider.DocumentsContract.buildDocumentUriUsingTree;
-import static android.provider.DocumentsContract.createDocument;
-import static android.provider.DocumentsContract.getTreeDocumentId;
 import static com.stevesoltys.backup.Backup.JOB_ID_BACKGROUND_BACKUP;
 import static com.stevesoltys.backup.activity.MainActivity.OPEN_DOCUMENT_TREE_BACKUP_REQUEST_CODE;
 import static com.stevesoltys.backup.activity.MainActivity.OPEN_DOCUMENT_TREE_REQUEST_CODE;
@@ -47,27 +38,16 @@
  */
 public class MainActivityController {
 
-    private static final String TAG = MainActivityController.class.getName();
-
-    private static final String DOCUMENT_MIME_TYPE = "application/octet-stream";
-    private static final String DOCUMENT_SUFFIX = "yyyy-MM-dd_HH_mm_ss";
+    public static final String DOCUMENT_MIME_TYPE = "application/octet-stream";
 
     void onBackupButtonClicked(Activity parent) {
         Uri folderUri = getBackupFolderUri(parent);
         if (folderUri == null) {
             showChooseFolderActivity(parent, true);
         } else {
-            try {
-                // ensure that backup service is started
-                parent.startService(new Intent(parent, ConfigurableBackupTransportService.class));
-
-                Uri fileUri = createBackupFile(parent.getContentResolver(), folderUri);
-                showCreateBackupActivity(parent, fileUri);
-
-            } catch (IOException e) {
-                Log.w(TAG, "Error creating backup file: ", e);
-                showChooseFolderActivity(parent, true);
-            }
+            // ensure that backup service is started
+            parent.startService(new Intent(parent, ConfigurableBackupTransportService.class));
+            showCreateBackupActivity(parent);
         }
     }
 
@@ -148,22 +128,11 @@
 
         if (!continueToBackup) return;
 
-        try {
-            // create a new backup file in folder
-            Uri fileUri = createBackupFile(contentResolver, folderUri);
-
-            showCreateBackupActivity(parent, fileUri);
-
-        } catch (IOException e) {
-            Log.e(TAG, "Error creating backup file: ", e);
-            // TODO show better error message once more infrastructure is in place
-            Toast.makeText(parent, "Error creating backup file", Toast.LENGTH_SHORT).show();
-        }
+        showCreateBackupActivity(parent);
     }
 
-    private void showCreateBackupActivity(Activity parent, Uri fileUri) {
+    private void showCreateBackupActivity(Activity parent) {
         Intent intent = new Intent(parent, CreateBackupActivity.class);
-        intent.setData(fileUri);
         parent.startActivity(intent);
     }
 
@@ -178,23 +147,4 @@
         parent.startActivity(intent);
     }
 
-    public static Uri createBackupFile(ContentResolver contentResolver, Uri folderUri) throws IOException {
-        Uri documentUri = buildDocumentUriUsingTree(folderUri, getTreeDocumentId(folderUri));
-        try {
-            Uri fileUri = createDocument(contentResolver, documentUri, DOCUMENT_MIME_TYPE, getBackupFileName());
-            if (fileUri == null) throw new IOException();
-            return fileUri;
-
-        } catch (SecurityException e) {
-            // happens when folder was deleted and thus Uri permission don't exist anymore
-            throw new IOException(e);
-        }
-    }
-
-    private static String getBackupFileName() {
-        SimpleDateFormat dateFormat = new SimpleDateFormat(DOCUMENT_SUFFIX, Locale.US);
-        String date = dateFormat.format(new Date());
-        return "backup-" + date;
-    }
-
 }
diff --git a/app/src/main/java/com/stevesoltys/backup/activity/backup/CreateBackupActivity.java b/app/src/main/java/com/stevesoltys/backup/activity/backup/CreateBackupActivity.java
index 7ac6e25..cdfc054 100644
--- a/app/src/main/java/com/stevesoltys/backup/activity/backup/CreateBackupActivity.java
+++ b/app/src/main/java/com/stevesoltys/backup/activity/backup/CreateBackupActivity.java
@@ -1,6 +1,5 @@
 package com.stevesoltys.backup.activity.backup;
 
-import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.view.Menu;
@@ -16,14 +15,12 @@
 
     private CreateBackupActivityController controller;
 
-    private Uri contentUri;
-
     @Override
     public void onClick(View view) {
         int viewId = view.getId();
 
         if (viewId == R.id.create_confirm_button) {
-            controller.onCreateBackupButtonClicked(selectedPackageList, contentUri, this);
+            controller.onCreateBackupButtonClicked(selectedPackageList, this);
         }
     }
 
@@ -36,7 +33,6 @@
 
         packageListView = findViewById(R.id.create_package_list);
         selectedPackageList = new HashSet<>();
-        contentUri = getIntent().getData();
 
         controller = new CreateBackupActivityController();
         AsyncTask.execute(() -> controller.populatePackageList(packageListView, CreateBackupActivity.this));
diff --git a/app/src/main/java/com/stevesoltys/backup/activity/backup/CreateBackupActivityController.java b/app/src/main/java/com/stevesoltys/backup/activity/backup/CreateBackupActivityController.java
index 67d2c15..74cbf4b 100644
--- a/app/src/main/java/com/stevesoltys/backup/activity/backup/CreateBackupActivityController.java
+++ b/app/src/main/java/com/stevesoltys/backup/activity/backup/CreateBackupActivityController.java
@@ -2,7 +2,6 @@
 
 import android.app.Activity;
 import android.app.AlertDialog;
-import android.net.Uri;
 import android.os.RemoteException;
 import android.text.InputType;
 import android.util.Log;
@@ -75,16 +74,16 @@
         });
     }
 
-    void onCreateBackupButtonClicked(Set<String> selectedPackages, Uri contentUri, Activity parent) {
+    void onCreateBackupButtonClicked(Set<String> selectedPackages, Activity parent) {
         String password = SettingsManager.getBackupPassword(parent);
         if (password == null) {
-            showEnterPasswordAlert(selectedPackages, contentUri, parent);
+            showEnterPasswordAlert(selectedPackages, parent);
         } else {
-            backupService.backupPackageData(selectedPackages, contentUri, parent, password);
+            backupService.backupPackageData(selectedPackages, parent);
         }
     }
 
-    private void showEnterPasswordAlert(Set<String> selectedPackages, Uri contentUri, Activity parent) {
+    private void showEnterPasswordAlert(Set<String> selectedPackages, Activity parent) {
         final EditText passwordTextView = new EditText(parent);
         passwordTextView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
 
@@ -97,9 +96,9 @@
                     if (passwordTextView.getText().length() == 0) {
                         Toast.makeText(parent, "Please enter a password", Toast.LENGTH_SHORT).show();
                         dialog.cancel();
-                        showEnterPasswordAlert(selectedPackages, contentUri, parent);
+                        showEnterPasswordAlert(selectedPackages, parent);
                     } else {
-                        showConfirmPasswordAlert(selectedPackages, contentUri, parent,
+                        showConfirmPasswordAlert(selectedPackages, parent,
                                 passwordTextView.getText().toString());
                     }
                 })
@@ -108,7 +107,7 @@
                 .show();
     }
 
-    private void showConfirmPasswordAlert(Set<String> selectedPackages, Uri contentUri, Activity parent,
+    private void showConfirmPasswordAlert(Set<String> selectedPackages, Activity parent,
                                           String originalPassword) {
         final EditText passwordTextView = new EditText(parent);
         passwordTextView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
@@ -122,7 +121,7 @@
 
                     if (originalPassword.equals(password)) {
                         SettingsManager.setBackupPassword(parent, password);
-                        backupService.backupPackageData(selectedPackages, contentUri, parent, password);
+                        backupService.backupPackageData(selectedPackages, parent);
 
                     } else {
                         new AlertDialog.Builder(parent)
diff --git a/app/src/main/java/com/stevesoltys/backup/activity/restore/RestoreBackupActivityController.java b/app/src/main/java/com/stevesoltys/backup/activity/restore/RestoreBackupActivityController.java
index 6370d7e..ed3ed75 100644
--- a/app/src/main/java/com/stevesoltys/backup/activity/restore/RestoreBackupActivityController.java
+++ b/app/src/main/java/com/stevesoltys/backup/activity/restore/RestoreBackupActivityController.java
@@ -7,12 +7,15 @@
 import android.text.InputType;
 import android.util.Log;
 import android.view.View;
-import android.widget.*;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.PopupWindow;
+import android.widget.TextView;
+
 import com.stevesoltys.backup.R;
 import com.stevesoltys.backup.activity.PopupWindowUtil;
 import com.stevesoltys.backup.service.restore.RestoreService;
-import com.stevesoltys.backup.transport.component.provider.ContentProviderBackupConfigurationBuilder;
-import libcore.io.IoUtils;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -24,6 +27,10 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 
+import libcore.io.IoUtils;
+
+import static com.stevesoltys.backup.transport.ConfigurableBackupTransport.DEFAULT_FULL_BACKUP_DIRECTORY;
+
 /**
  * @author Steve Soltys
  */
@@ -76,7 +83,7 @@
         while ((zipEntry = inputStream.getNextEntry()) != null) {
             String zipEntryPath = zipEntry.getName();
 
-            if (zipEntryPath.startsWith(ContentProviderBackupConfigurationBuilder.DEFAULT_FULL_BACKUP_DIRECTORY)) {
+            if (zipEntryPath.startsWith(DEFAULT_FULL_BACKUP_DIRECTORY)) {
                 String fileName = new File(zipEntryPath).getName();
                 results.add(fileName);
             }
diff --git a/app/src/main/java/com/stevesoltys/backup/service/TransportService.java b/app/src/main/java/com/stevesoltys/backup/service/TransportService.java
index 934005b..9dcbca4 100644
--- a/app/src/main/java/com/stevesoltys/backup/service/TransportService.java
+++ b/app/src/main/java/com/stevesoltys/backup/service/TransportService.java
@@ -3,17 +3,11 @@
 import android.app.backup.IBackupManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+
 import com.stevesoltys.backup.session.backup.BackupSession;
 import com.stevesoltys.backup.session.backup.BackupSessionObserver;
 import com.stevesoltys.backup.session.restore.RestoreSession;
 import com.stevesoltys.backup.session.restore.RestoreSessionObserver;
-import com.stevesoltys.backup.transport.ConfigurableBackupTransport;
-import com.stevesoltys.backup.transport.ConfigurableBackupTransportService;
-import com.stevesoltys.backup.transport.component.BackupComponent;
-import com.stevesoltys.backup.transport.component.RestoreComponent;
-import com.stevesoltys.backup.transport.component.provider.ContentProviderBackupComponent;
-import com.stevesoltys.backup.transport.component.provider.ContentProviderBackupConfiguration;
-import com.stevesoltys.backup.transport.component.provider.ContentProviderRestoreComponent;
 
 import java.util.Set;
 
@@ -30,19 +24,6 @@
         backupManager = IBackupManager.Stub.asInterface(ServiceManager.getService("backup"));
     }
 
-    public boolean initializeBackupTransport(ContentProviderBackupConfiguration configuration) {
-        ConfigurableBackupTransport backupTransport = ConfigurableBackupTransportService.getBackupTransport();
-
-        if (backupTransport.isActive()) {
-            return false;
-        }
-
-        BackupComponent backupComponent = new ContentProviderBackupComponent(configuration);
-        RestoreComponent restoreComponent = new ContentProviderRestoreComponent(configuration);
-        backupTransport.initialize(backupComponent, restoreComponent);
-        return true;
-    }
-
     public BackupSession backup(BackupSessionObserver observer, Set<String> packages) throws RemoteException {
 
         if (!BACKUP_TRANSPORT.equals(backupManager.getCurrentTransport())) {
diff --git a/app/src/main/java/com/stevesoltys/backup/service/backup/BackupJobService.java b/app/src/main/java/com/stevesoltys/backup/service/backup/BackupJobService.java
index 1bcc399..6726060 100644
--- a/app/src/main/java/com/stevesoltys/backup/service/backup/BackupJobService.java
+++ b/app/src/main/java/com/stevesoltys/backup/service/backup/BackupJobService.java
@@ -5,27 +5,20 @@
 import android.app.job.JobParameters;
 import android.app.job.JobService;
 import android.content.Intent;
-import android.net.Uri;
 import android.os.RemoteException;
 import android.util.Log;
 
 import com.google.android.collect.Sets;
 import com.stevesoltys.backup.service.PackageService;
-import com.stevesoltys.backup.service.TransportService;
+import com.stevesoltys.backup.transport.ConfigurableBackupTransport;
 import com.stevesoltys.backup.transport.ConfigurableBackupTransportService;
-import com.stevesoltys.backup.transport.component.provider.ContentProviderBackupConfiguration;
-import com.stevesoltys.backup.transport.component.provider.ContentProviderBackupConfigurationBuilder;
 
-import java.io.IOException;
-import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.Set;
 
 import static android.app.backup.BackupManager.FLAG_NON_INCREMENTAL_BACKUP;
 import static android.os.ServiceManager.getService;
-import static com.stevesoltys.backup.activity.MainActivityController.createBackupFile;
-import static com.stevesoltys.backup.settings.SettingsManager.getBackupFolderUri;
-import static com.stevesoltys.backup.settings.SettingsManager.getBackupPassword;
+import static com.stevesoltys.backup.transport.ConfigurableBackupTransportService.getBackupTransport;
 
 public class BackupJobService extends JobService {
 
@@ -37,7 +30,6 @@
     );
 
     private final IBackupManager backupManager;
-    private final TransportService transportService = new TransportService();
 
     public BackupJobService() {
         backupManager = IBackupManager.Stub.asInterface(getService("backup"));
@@ -50,17 +42,10 @@
         try {
             LinkedList<String> packages = new LinkedList<>(new PackageService().getEligiblePackages());
             packages.removeAll(IGNORED_PACKAGES);
-            Uri fileUri = createBackupFile(getContentResolver(), getBackupFolderUri(this));
-            ContentProviderBackupConfiguration backupConfiguration = new ContentProviderBackupConfigurationBuilder()
-                    .setContext(this)
-                    .setPackages(new HashSet<>(packages))
-                    .setOutputUri(fileUri)
-                    .setPassword(getBackupPassword(this))
-                    .build();
-            transportService.initializeBackupTransport(backupConfiguration);
-
             // TODO use an observer to know when backups fail
             String[] packageArray = packages.toArray(new String[packages.size()]);
+            ConfigurableBackupTransport backupTransport = getBackupTransport(getApplication());
+            backupTransport.prepareBackup(packageArray.length);
             int result = backupManager.requestBackup(packageArray, null, null, FLAG_NON_INCREMENTAL_BACKUP);
             if (result == BackupManager.SUCCESS) {
                 Log.i(TAG, "Backup succeeded ");
@@ -69,8 +54,6 @@
             }
 
         // TODO show notification on backup error
-        } catch (IOException e) {
-            Log.e(TAG, "Error creating backup file: ", e);
         } catch (RemoteException e) {
             Log.e(TAG, "Error during backup: ", e);
         } finally {
diff --git a/app/src/main/java/com/stevesoltys/backup/service/backup/BackupObserver.java b/app/src/main/java/com/stevesoltys/backup/service/backup/BackupObserver.java
index abd2d07..8bcbfef 100644
--- a/app/src/main/java/com/stevesoltys/backup/service/backup/BackupObserver.java
+++ b/app/src/main/java/com/stevesoltys/backup/service/backup/BackupObserver.java
@@ -6,14 +6,11 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 import android.widget.Toast;
+
 import com.stevesoltys.backup.R;
 import com.stevesoltys.backup.session.backup.BackupResult;
 import com.stevesoltys.backup.session.backup.BackupSession;
 import com.stevesoltys.backup.session.backup.BackupSessionObserver;
-import com.stevesoltys.backup.transport.ConfigurableBackupTransport;
-import com.stevesoltys.backup.transport.ConfigurableBackupTransportService;
-
-import java.net.URI;
 
 /**
  * @author Steve Soltys
@@ -24,12 +21,9 @@
 
     private final PopupWindow popupWindow;
 
-    private final URI contentUri;
-
-    BackupObserver(Activity context, PopupWindow popupWindow, URI contentUri) {
+    BackupObserver(Activity context, PopupWindow popupWindow) {
         this.context = context;
         this.popupWindow = popupWindow;
-        this.contentUri = contentUri;
     }
 
     @Override
@@ -65,14 +59,6 @@
 
     @Override
     public void backupSessionCompleted(BackupSession backupSession, BackupResult backupResult) {
-        ConfigurableBackupTransport backupTransport = ConfigurableBackupTransportService.getBackupTransport();
-
-        if (!backupTransport.isActive()) {
-            return;
-        }
-
-        backupTransport.reset();
-
         context.runOnUiThread(() -> {
             if (backupResult == BackupResult.SUCCESS) {
                 Toast.makeText(context, R.string.backup_success, Toast.LENGTH_LONG).show();
diff --git a/app/src/main/java/com/stevesoltys/backup/service/backup/BackupService.java b/app/src/main/java/com/stevesoltys/backup/service/backup/BackupService.java
index 3795170..84be267 100644
--- a/app/src/main/java/com/stevesoltys/backup/service/backup/BackupService.java
+++ b/app/src/main/java/com/stevesoltys/backup/service/backup/BackupService.java
@@ -1,23 +1,22 @@
 package com.stevesoltys.backup.service.backup;
 
 import android.app.Activity;
-import android.net.Uri;
 import android.util.Log;
 import android.view.View;
 import android.widget.PopupWindow;
 import android.widget.TextView;
-import android.widget.Toast;
+
 import com.stevesoltys.backup.R;
 import com.stevesoltys.backup.activity.PopupWindowUtil;
 import com.stevesoltys.backup.activity.backup.BackupPopupWindowListener;
 import com.stevesoltys.backup.service.TransportService;
 import com.stevesoltys.backup.session.backup.BackupSession;
-import com.stevesoltys.backup.transport.component.provider.ContentProviderBackupConfiguration;
-import com.stevesoltys.backup.transport.component.provider.ContentProviderBackupConfigurationBuilder;
+import com.stevesoltys.backup.transport.ConfigurableBackupTransport;
 
-import java.net.URI;
 import java.util.Set;
 
+import static com.stevesoltys.backup.transport.ConfigurableBackupTransportService.getBackupTransport;
+
 /**
  * @author Steve Soltys
  */
@@ -27,27 +26,14 @@
 
     private final TransportService transportService = new TransportService();
 
-    public void backupPackageData(Set<String> selectedPackages, Uri contentUri, Activity parent,
-                                  String selectedPassword) {
+    public void backupPackageData(Set<String> selectedPackages, Activity parent) {
         try {
             selectedPackages.add("@pm@");
 
-            ContentProviderBackupConfiguration backupConfiguration = new ContentProviderBackupConfigurationBuilder()
-                    .setContext(parent)
-                    .setOutputUri(contentUri)
-                    .setPackages(selectedPackages)
-                    .setPassword(selectedPassword)
-                    .build();
-
-            boolean success = transportService.initializeBackupTransport(backupConfiguration);
-
-            if (!success) {
-                Toast.makeText(parent, R.string.backup_in_progress, Toast.LENGTH_LONG).show();
-                return;
-            }
-
             PopupWindow popupWindow = PopupWindowUtil.showLoadingPopupWindow(parent);
-            BackupObserver backupObserver = new BackupObserver(parent, popupWindow, new URI(contentUri.getPath()));
+            BackupObserver backupObserver = new BackupObserver(parent, popupWindow);
+            ConfigurableBackupTransport backupTransport = getBackupTransport(parent.getApplication());
+            backupTransport.prepareBackup(selectedPackages.size());
             BackupSession backupSession = transportService.backup(backupObserver, selectedPackages);
 
             View popupWindowButton = popupWindow.getContentView().findViewById(R.id.popup_cancel_button);
diff --git a/app/src/main/java/com/stevesoltys/backup/service/restore/RestoreObserver.java b/app/src/main/java/com/stevesoltys/backup/service/restore/RestoreObserver.java
index 69caa69..d7132af 100644
--- a/app/src/main/java/com/stevesoltys/backup/service/restore/RestoreObserver.java
+++ b/app/src/main/java/com/stevesoltys/backup/service/restore/RestoreObserver.java
@@ -5,11 +5,10 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 import android.widget.Toast;
+
 import com.stevesoltys.backup.R;
 import com.stevesoltys.backup.session.restore.RestoreResult;
 import com.stevesoltys.backup.session.restore.RestoreSessionObserver;
-import com.stevesoltys.backup.transport.ConfigurableBackupTransport;
-import com.stevesoltys.backup.transport.ConfigurableBackupTransportService;
 
 /**
  * @author Steve Soltys
@@ -56,14 +55,6 @@
 
     @Override
     public void restoreSessionCompleted(RestoreResult restoreResult) {
-        ConfigurableBackupTransport backupTransport = ConfigurableBackupTransportService.getBackupTransport();
-
-        if (!backupTransport.isActive()) {
-            return;
-        }
-
-        backupTransport.reset();
-
         context.runOnUiThread(() -> {
             if (restoreResult == RestoreResult.SUCCESS) {
                 Toast.makeText(context, R.string.restore_success, Toast.LENGTH_LONG).show();
diff --git a/app/src/main/java/com/stevesoltys/backup/service/restore/RestoreService.java b/app/src/main/java/com/stevesoltys/backup/service/restore/RestoreService.java
index 06e15c0..6441397 100644
--- a/app/src/main/java/com/stevesoltys/backup/service/restore/RestoreService.java
+++ b/app/src/main/java/com/stevesoltys/backup/service/restore/RestoreService.java
@@ -6,17 +6,18 @@
 import android.util.Log;
 import android.view.View;
 import android.widget.PopupWindow;
-import android.widget.Toast;
+
 import com.stevesoltys.backup.R;
 import com.stevesoltys.backup.activity.PopupWindowUtil;
 import com.stevesoltys.backup.activity.restore.RestorePopupWindowListener;
 import com.stevesoltys.backup.service.TransportService;
 import com.stevesoltys.backup.session.restore.RestoreSession;
-import com.stevesoltys.backup.transport.component.provider.ContentProviderBackupConfiguration;
-import com.stevesoltys.backup.transport.component.provider.ContentProviderBackupConfigurationBuilder;
+import com.stevesoltys.backup.transport.ConfigurableBackupTransport;
 
 import java.util.Set;
 
+import static com.stevesoltys.backup.transport.ConfigurableBackupTransportService.getBackupTransport;
+
 /**
  * @author Steve Soltys
  */
@@ -27,21 +28,9 @@
     private final TransportService transportService = new TransportService();
 
     public void restorePackages(Set<String> selectedPackages, Uri contentUri, Activity parent, String password) {
+        ConfigurableBackupTransport backupTransport = getBackupTransport(parent.getApplication());
+        backupTransport.prepareRestore(password, contentUri);
         try {
-            ContentProviderBackupConfiguration backupConfiguration = new ContentProviderBackupConfigurationBuilder().
-                    setContext(parent)
-                    .setOutputUri(contentUri)
-                    .setPackages(selectedPackages)
-                    .setPassword(password)
-                    .build();
-
-            boolean success = transportService.initializeBackupTransport(backupConfiguration);
-
-            if (!success) {
-                Toast.makeText(parent, R.string.restore_in_progress, Toast.LENGTH_LONG).show();
-                return;
-            }
-
             PopupWindow popupWindow = PopupWindowUtil.showLoadingPopupWindow(parent);
             RestoreObserver restoreObserver = new RestoreObserver(parent, popupWindow, selectedPackages.size());
             RestoreSession restoreSession = transportService.restore(restoreObserver, selectedPackages);
diff --git a/app/src/main/java/com/stevesoltys/backup/transport/ConfigurableBackupTransport.java b/app/src/main/java/com/stevesoltys/backup/transport/ConfigurableBackupTransport.java
index 6cddb1a..505b067 100644
--- a/app/src/main/java/com/stevesoltys/backup/transport/ConfigurableBackupTransport.java
+++ b/app/src/main/java/com/stevesoltys/backup/transport/ConfigurableBackupTransport.java
@@ -3,14 +3,15 @@
 import android.app.backup.BackupTransport;
 import android.app.backup.RestoreDescription;
 import android.app.backup.RestoreSet;
+import android.content.Context;
 import android.content.pm.PackageInfo;
+import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 
-import com.android.internal.util.Preconditions;
 import com.stevesoltys.backup.transport.component.BackupComponent;
 import com.stevesoltys.backup.transport.component.RestoreComponent;
-import com.stevesoltys.backup.transport.component.stub.StubBackupComponent;
-import com.stevesoltys.backup.transport.component.stub.StubRestoreComponent;
+import com.stevesoltys.backup.transport.component.provider.ContentProviderBackupComponent;
+import com.stevesoltys.backup.transport.component.provider.ContentProviderRestoreComponent;
 
 /**
  * @author Steve Soltys
@@ -20,31 +21,27 @@
     private static final String TRANSPORT_DIRECTORY_NAME =
             "com.stevesoltys.backup.transport.ConfigurableBackupTransport";
 
-    private BackupComponent backupComponent;
+    public static final String DEFAULT_FULL_BACKUP_DIRECTORY = "full/";
 
-    private RestoreComponent restoreComponent;
+    public static final String DEFAULT_INCREMENTAL_BACKUP_DIRECTORY = "incr/";
 
-    ConfigurableBackupTransport() {
-        backupComponent = new StubBackupComponent();
-        restoreComponent = new StubRestoreComponent();
+    public static final long DEFAULT_BACKUP_QUOTA = Long.MAX_VALUE;
+
+    private final BackupComponent backupComponent;
+
+    private final RestoreComponent restoreComponent;
+
+    ConfigurableBackupTransport(Context context) {
+        backupComponent = new ContentProviderBackupComponent(context);
+        restoreComponent = new ContentProviderRestoreComponent(context);
     }
 
-    public void initialize(BackupComponent backupComponent, RestoreComponent restoreComponent) {
-        Preconditions.checkNotNull(backupComponent);
-        Preconditions.checkNotNull(restoreComponent);
-        Preconditions.checkState(!isActive());
-
-        this.restoreComponent = restoreComponent;
-        this.backupComponent = backupComponent;
+    public void prepareBackup(int numberOfPackages) {
+        backupComponent.prepareBackup(numberOfPackages);
     }
 
-    public void reset() {
-        backupComponent = new StubBackupComponent();
-        restoreComponent = new StubRestoreComponent();
-    }
-
-    public boolean isActive() {
-        return !(backupComponent instanceof StubBackupComponent || restoreComponent instanceof StubRestoreComponent);
+    public void prepareRestore(String password, Uri fileUri) {
+        restoreComponent.prepareRestore(password, fileUri);
     }
 
     @Override
diff --git a/app/src/main/java/com/stevesoltys/backup/transport/ConfigurableBackupTransportService.java b/app/src/main/java/com/stevesoltys/backup/transport/ConfigurableBackupTransportService.java
index 89d74e1..da89688 100644
--- a/app/src/main/java/com/stevesoltys/backup/transport/ConfigurableBackupTransportService.java
+++ b/app/src/main/java/com/stevesoltys/backup/transport/ConfigurableBackupTransportService.java
@@ -1,6 +1,7 @@
 package com.stevesoltys.backup.transport;
 
 import android.app.Service;
+import android.content.Context;
 import android.content.Intent;
 import android.os.IBinder;
 import android.util.Log;
@@ -14,10 +15,10 @@
 
     private static ConfigurableBackupTransport backupTransport = null;
 
-    public static ConfigurableBackupTransport getBackupTransport() {
+    public static ConfigurableBackupTransport getBackupTransport(Context context) {
 
         if (backupTransport == null) {
-            backupTransport = new ConfigurableBackupTransport();
+            backupTransport = new ConfigurableBackupTransport(context);
         }
 
         return backupTransport;
@@ -31,7 +32,7 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        return getBackupTransport().getBinder();
+        return getBackupTransport(getApplicationContext()).getBinder();
     }
 
     @Override
diff --git a/app/src/main/java/com/stevesoltys/backup/transport/component/BackupComponent.java b/app/src/main/java/com/stevesoltys/backup/transport/component/BackupComponent.java
index 1fafbe6..f3c7cd4 100644
--- a/app/src/main/java/com/stevesoltys/backup/transport/component/BackupComponent.java
+++ b/app/src/main/java/com/stevesoltys/backup/transport/component/BackupComponent.java
@@ -8,6 +8,8 @@
  */
 public interface BackupComponent {
 
+    void prepareBackup(int numberOfPackages);
+
     String currentDestinationString();
 
     String dataManagementLabel();
diff --git a/app/src/main/java/com/stevesoltys/backup/transport/component/RestoreComponent.java b/app/src/main/java/com/stevesoltys/backup/transport/component/RestoreComponent.java
index 2873cf1..08f866a 100644
--- a/app/src/main/java/com/stevesoltys/backup/transport/component/RestoreComponent.java
+++ b/app/src/main/java/com/stevesoltys/backup/transport/component/RestoreComponent.java
@@ -3,6 +3,7 @@
 import android.app.backup.RestoreDescription;
 import android.app.backup.RestoreSet;
 import android.content.pm.PackageInfo;
+import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 
 /**
@@ -10,6 +11,8 @@
  */
 public interface RestoreComponent {
 
+    void prepareRestore(String password, Uri fileUri);
+
     int startRestore(long token, PackageInfo[] packages);
 
     RestoreDescription nextRestorePackage();
diff --git a/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderBackupComponent.java b/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderBackupComponent.java
index 1100c59..e964ec6 100644
--- a/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderBackupComponent.java
+++ b/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderBackupComponent.java
@@ -1,28 +1,47 @@
 package com.stevesoltys.backup.transport.component.provider;
 
 import android.app.backup.BackupDataInput;
-import android.content.ContentResolver;
+import android.content.Context;
 import android.content.pm.PackageInfo;
+import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 import android.util.Base64;
 import android.util.Log;
+
 import com.stevesoltys.backup.security.CipherUtil;
 import com.stevesoltys.backup.security.KeyGenerator;
+import com.stevesoltys.backup.settings.SettingsManager;
 import com.stevesoltys.backup.transport.component.BackupComponent;
-import libcore.io.IoUtils;
+
 import org.apache.commons.io.IOUtils;
 
-import javax.crypto.Cipher;
-import javax.crypto.SecretKey;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.text.SimpleDateFormat;
 import java.util.Arrays;
+import java.util.Date;
+import java.util.Locale;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
-import static android.app.backup.BackupTransport.*;
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+
+import libcore.io.IoUtils;
+
+import static android.app.backup.BackupTransport.TRANSPORT_ERROR;
+import static android.app.backup.BackupTransport.TRANSPORT_OK;
+import static android.app.backup.BackupTransport.TRANSPORT_PACKAGE_REJECTED;
+import static android.app.backup.BackupTransport.TRANSPORT_QUOTA_EXCEEDED;
+import static android.provider.DocumentsContract.buildDocumentUriUsingTree;
+import static android.provider.DocumentsContract.createDocument;
+import static android.provider.DocumentsContract.getTreeDocumentId;
+import static com.stevesoltys.backup.activity.MainActivityController.DOCUMENT_MIME_TYPE;
+import static com.stevesoltys.backup.transport.ConfigurableBackupTransport.DEFAULT_BACKUP_QUOTA;
+import static com.stevesoltys.backup.transport.ConfigurableBackupTransport.DEFAULT_FULL_BACKUP_DIRECTORY;
+import static com.stevesoltys.backup.transport.ConfigurableBackupTransport.DEFAULT_INCREMENTAL_BACKUP_DIRECTORY;
 import static java.util.Objects.requireNonNull;
 
 /**
@@ -32,18 +51,22 @@
 
     private static final String TAG = ContentProviderBackupComponent.class.getName();
 
+    private static final String DOCUMENT_SUFFIX = "yyyy-MM-dd_HH_mm_ss";
+
     private static final String DESTINATION_DESCRIPTION = "Backing up to zip file";
 
     private static final String TRANSPORT_DATA_MANAGEMENT_LABEL = "";
 
     private static final int INITIAL_BUFFER_SIZE = 512;
 
-    private final ContentProviderBackupConfiguration configuration;
+    private final Context context;
+
+    private int numberOfPackages = 0;
 
     private ContentProviderBackupState backupState;
 
-    public ContentProviderBackupComponent(ContentProviderBackupConfiguration configuration) {
-        this.configuration = configuration;
+    public ContentProviderBackupComponent(Context context) {
+        this.context = context;
     }
 
     @Override
@@ -58,7 +81,7 @@
         if (size <= 0) {
             result = TRANSPORT_PACKAGE_REJECTED;
 
-        } else if (size > configuration.getBackupSizeQuota()) {
+        } else if (size > DEFAULT_BACKUP_QUOTA) {
             result = TRANSPORT_QUOTA_EXCEEDED;
         }
 
@@ -71,6 +94,11 @@
     }
 
     @Override
+    public void prepareBackup(int numberOfPackages) {
+        this.numberOfPackages = numberOfPackages;
+    }
+
+    @Override
     public String currentDestinationString() {
         return DESTINATION_DESCRIPTION;
     }
@@ -87,7 +115,7 @@
 
     @Override
     public long getBackupQuota(String packageName, boolean fullBackup) {
-        return configuration.getBackupSizeQuota();
+        return DEFAULT_BACKUP_QUOTA;
     }
 
     @Override
@@ -115,7 +143,7 @@
             Cipher cipher = CipherUtil.startEncrypt(backupState.getSecretKey(), backupState.getSalt());
             backupState.setCipher(cipher);
 
-            ZipEntry zipEntry = new ZipEntry(configuration.getFullBackupDirectory() + backupState.getPackageName());
+            ZipEntry zipEntry = new ZipEntry(DEFAULT_FULL_BACKUP_DIRECTORY + backupState.getPackageName());
             backupState.getOutputStream().putNextEntry(zipEntry);
 
         } catch (Exception ex) {
@@ -164,7 +192,7 @@
 
         long bytesTransferred = backupState.getBytesTransferred() + numBytes;
 
-        if (bytesTransferred > configuration.getBackupSizeQuota()) {
+        if (bytesTransferred > DEFAULT_BACKUP_QUOTA) {
             return TRANSPORT_QUOTA_EXCEEDED;
         }
 
@@ -199,7 +227,7 @@
             int dataSize = backupDataInput.getDataSize();
 
             if (dataSize >= 0) {
-                ZipEntry zipEntry = new ZipEntry(configuration.getIncrementalBackupDirectory() +
+                ZipEntry zipEntry = new ZipEntry(DEFAULT_INCREMENTAL_BACKUP_DIRECTORY +
                         backupState.getPackageName() + "/" + chunkFileName);
                 outputStream.putNextEntry(zipEntry);
 
@@ -246,14 +274,18 @@
             backupState.getOutputStream().write(backupState.getSalt());
             backupState.getOutputStream().closeEntry();
 
-            String password = requireNonNull(configuration.getPassword());
+            String password = requireNonNull(SettingsManager.getBackupPassword(context));
             backupState.setSecretKey(KeyGenerator.generate(password, backupState.getSalt()));
         }
     }
 
     private void initializeOutputStream() throws IOException {
-        ContentResolver contentResolver = configuration.getContext().getContentResolver();
-        ParcelFileDescriptor outputFileDescriptor = contentResolver.openFileDescriptor(configuration.getUri(), "w");
+        Uri folderUri = SettingsManager.getBackupFolderUri(context);
+        // TODO notify about failure with notification
+        Uri fileUri = createBackupFile(folderUri);
+
+        ParcelFileDescriptor outputFileDescriptor = context.getContentResolver().openFileDescriptor(fileUri, "w");
+        if (outputFileDescriptor == null) throw new IOException();
         backupState.setOutputFileDescriptor(outputFileDescriptor);
 
         FileOutputStream fileOutputStream = new FileOutputStream(outputFileDescriptor.getFileDescriptor());
@@ -261,6 +293,25 @@
         backupState.setOutputStream(zipOutputStream);
     }
 
+    private Uri createBackupFile(Uri folderUri) throws IOException {
+        Uri documentUri = buildDocumentUriUsingTree(folderUri, getTreeDocumentId(folderUri));
+        try {
+            Uri fileUri = createDocument(context.getContentResolver(), documentUri, DOCUMENT_MIME_TYPE, getBackupFileName());
+            if (fileUri == null) throw new IOException();
+            return fileUri;
+
+        } catch (SecurityException e) {
+            // happens when folder was deleted and thus Uri permission don't exist anymore
+            throw new IOException(e);
+        }
+    }
+
+    private String getBackupFileName() {
+        SimpleDateFormat dateFormat = new SimpleDateFormat(DOCUMENT_SUFFIX, Locale.US);
+        String date = dateFormat.format(new Date());
+        return "backup-" + date;
+    }
+
     private int clearBackupState(boolean closeFile) {
 
         if (backupState == null) {
@@ -283,7 +334,7 @@
                 outputStream.closeEntry();
             }
 
-            if (backupState.getPackageIndex() == configuration.getPackageCount() || closeFile) {
+            if (backupState.getPackageIndex() == numberOfPackages || closeFile) {
                 if (outputStream != null) {
                     outputStream.finish();
                     outputStream.close();
diff --git a/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderBackupConfiguration.java b/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderBackupConfiguration.java
deleted file mode 100644
index bf90d5e..0000000
--- a/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderBackupConfiguration.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.stevesoltys.backup.transport.component.provider;
-
-import android.content.Context;
-import android.net.Uri;
-
-import java.util.Set;
-
-/**
- * @author Steve Soltys
- */
-public class ContentProviderBackupConfiguration {
-
-    private final Context context;
-
-    private final Uri uri;
-
-    private final String password;
-
-    private final long backupSizeQuota;
-
-    private final Set<String> packages;
-
-    private final String fullBackupDirectory;
-
-    private final String incrementalBackupDirectory;
-
-    ContentProviderBackupConfiguration(Context context, Uri uri, Set<String> packages, String password,
-                                       long backupSizeQuota, String fullBackupDirectory,
-                                       String incrementalBackupDirectory) {
-        this.context = context;
-        this.uri = uri;
-        this.packages = packages;
-        this.password = password;
-        this.backupSizeQuota = backupSizeQuota;
-        this.fullBackupDirectory = fullBackupDirectory;
-        this.incrementalBackupDirectory = incrementalBackupDirectory;
-    }
-
-    public long getBackupSizeQuota() {
-        return backupSizeQuota;
-    }
-
-    public Context getContext() {
-        return context;
-    }
-
-    public String getFullBackupDirectory() {
-        return fullBackupDirectory;
-    }
-
-    public String getIncrementalBackupDirectory() {
-        return incrementalBackupDirectory;
-    }
-
-    public int getPackageCount() {
-        return packages.size();
-    }
-
-    public String getPassword() {
-        return password;
-    }
-
-    public Uri getUri() {
-        return uri;
-    }
-}
diff --git a/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderBackupConfigurationBuilder.java b/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderBackupConfigurationBuilder.java
deleted file mode 100644
index 0f63b8c..0000000
--- a/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderBackupConfigurationBuilder.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.stevesoltys.backup.transport.component.provider;
-
-import android.content.Context;
-import android.net.Uri;
-import com.android.internal.util.Preconditions;
-
-import java.util.Set;
-
-/**
- * @author Steve Soltys
- */
-public class ContentProviderBackupConfigurationBuilder {
-
-    public static final String DEFAULT_FULL_BACKUP_DIRECTORY = "full/";
-
-    public static final String DEFAULT_INCREMENTAL_BACKUP_DIRECTORY = "incr/";
-
-    private Context context;
-
-    private Uri outputUri;
-
-    private Set<String> packages;
-
-    private String password;
-
-    private long backupSizeQuota = Long.MAX_VALUE;
-
-    private String incrementalBackupDirectory = DEFAULT_INCREMENTAL_BACKUP_DIRECTORY;
-
-    private String fullBackupDirectory = DEFAULT_FULL_BACKUP_DIRECTORY;
-
-    public ContentProviderBackupConfiguration build() {
-        Preconditions.checkState(context != null, "Context must be set.");
-        Preconditions.checkState(outputUri != null, "Output URI must be set.");
-        Preconditions.checkState(packages != null, "Package list must be set.");
-        Preconditions.checkState(incrementalBackupDirectory != null, "Incremental backup directory must be set.");
-        Preconditions.checkState(fullBackupDirectory != null, "Full backup directory must be set.");
-
-        return new ContentProviderBackupConfiguration(context, outputUri, packages, password, backupSizeQuota,
-                fullBackupDirectory, incrementalBackupDirectory);
-    }
-
-    public ContentProviderBackupConfigurationBuilder setBackupSizeQuota(long backupSizeQuota) {
-        this.backupSizeQuota = backupSizeQuota;
-        return this;
-    }
-
-    public ContentProviderBackupConfigurationBuilder setContext(Context context) {
-        this.context = context;
-        return this;
-    }
-
-    public ContentProviderBackupConfigurationBuilder setFullBackupDirectory(String fullBackupDirectory) {
-        this.fullBackupDirectory = fullBackupDirectory;
-        return this;
-    }
-
-    public ContentProviderBackupConfigurationBuilder setIncrementalBackupDirectory(String incrementalBackupDirectory) {
-        this.incrementalBackupDirectory = incrementalBackupDirectory;
-        return this;
-    }
-
-    public ContentProviderBackupConfigurationBuilder setOutputUri(Uri outputUri) {
-        this.outputUri = outputUri;
-        return this;
-    }
-
-    public ContentProviderBackupConfigurationBuilder setPackages(Set<String> packages) {
-        this.packages = packages;
-        return this;
-    }
-
-    public ContentProviderBackupConfigurationBuilder setPassword(String password) {
-        this.password = password;
-        return this;
-    }
-}
diff --git a/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderRestoreComponent.java b/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderRestoreComponent.java
index 47aeeb5..05f1abc 100644
--- a/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderRestoreComponent.java
+++ b/app/src/main/java/com/stevesoltys/backup/transport/component/provider/ContentProviderRestoreComponent.java
@@ -1,10 +1,13 @@
 package com.stevesoltys.backup.transport.component.provider;
 
+import android.annotation.Nullable;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.RestoreDescription;
 import android.app.backup.RestoreSet;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.content.pm.PackageInfo;
+import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 import android.util.Base64;
 import android.util.Log;
@@ -38,6 +41,9 @@
 import static android.app.backup.BackupTransport.TRANSPORT_PACKAGE_REJECTED;
 import static android.app.backup.RestoreDescription.TYPE_FULL_STREAM;
 import static android.app.backup.RestoreDescription.TYPE_KEY_VALUE;
+import static com.stevesoltys.backup.transport.ConfigurableBackupTransport.DEFAULT_FULL_BACKUP_DIRECTORY;
+import static com.stevesoltys.backup.transport.ConfigurableBackupTransport.DEFAULT_INCREMENTAL_BACKUP_DIRECTORY;
+import static java.util.Objects.requireNonNull;
 
 /**
  * @author Steve Soltys
@@ -50,12 +56,23 @@
 
     private static final int DEFAULT_BUFFER_SIZE = 2048;
 
-    private ContentProviderBackupConfiguration configuration;
+    @Nullable
+    private String password;
+    @Nullable
+    private Uri fileUri;
 
     private ContentProviderRestoreState restoreState;
 
-    public ContentProviderRestoreComponent(ContentProviderBackupConfiguration configuration) {
-        this.configuration = configuration;
+    private final Context context;
+
+    public ContentProviderRestoreComponent(Context context) {
+        this.context = context;
+    }
+
+    @Override
+    public void prepareRestore(String password, Uri fileUri) {
+        this.password = password;
+        this.fileUri = fileUri;
     }
 
     @Override
@@ -64,14 +81,16 @@
         restoreState.setPackages(packages);
         restoreState.setPackageIndex(-1);
 
-        if (configuration.getPassword() != null && !configuration.getPassword().isEmpty()) {
+        String password = requireNonNull(this.password);
+
+        if (!password.isEmpty()) {
             try {
                 ParcelFileDescriptor inputFileDescriptor = buildInputFileDescriptor();
                 ZipInputStream inputStream = buildInputStream(inputFileDescriptor);
                 seekToEntry(inputStream, ContentProviderBackupConstants.SALT_FILE_PATH);
 
                 restoreState.setSalt(Streams.readFullyNoClose(inputStream));
-                restoreState.setSecretKey(KeyGenerator.generate(configuration.getPassword(), restoreState.getSalt()));
+                restoreState.setSecretKey(KeyGenerator.generate(password, restoreState.getSalt()));
 
                 IoUtils.closeQuietly(inputFileDescriptor);
                 IoUtils.closeQuietly(inputStream);
@@ -116,11 +135,11 @@
             restoreState.setPackageIndex(packageIndex);
             String name = packages[packageIndex].packageName;
 
-            if (containsPackageFile(configuration.getIncrementalBackupDirectory() + name)) {
+            if (containsPackageFile(DEFAULT_INCREMENTAL_BACKUP_DIRECTORY + name)) {
                 restoreState.setRestoreType(TYPE_KEY_VALUE);
                 return new RestoreDescription(name, restoreState.getRestoreType());
 
-            } else if (containsPackageFile(configuration.getFullBackupDirectory() + name)) {
+            } else if (containsPackageFile(DEFAULT_FULL_BACKUP_DIRECTORY + name)) {
                 restoreState.setRestoreType(TYPE_FULL_STREAM);
                 return new RestoreDescription(name, restoreState.getRestoreType());
             }
@@ -159,7 +178,7 @@
         BackupDataOutput backupDataOutput = new BackupDataOutput(outputFileDescriptor.getFileDescriptor());
 
         Optional<ZipEntry> zipEntryOptional = seekToEntry(inputStream,
-                configuration.getIncrementalBackupDirectory() + packageName);
+                DEFAULT_INCREMENTAL_BACKUP_DIRECTORY + packageName);
 
         while (zipEntryOptional.isPresent()) {
             String fileName = new File(zipEntryOptional.get().getName()).getName();
@@ -170,7 +189,7 @@
             backupDataOutput.writeEntityData(backupData, backupData.length);
             inputStream.closeEntry();
 
-            zipEntryOptional = seekToEntry(inputStream, configuration.getIncrementalBackupDirectory() + packageName);
+            zipEntryOptional = seekToEntry(inputStream, DEFAULT_INCREMENTAL_BACKUP_DIRECTORY + packageName);
         }
 
         IoUtils.closeQuietly(inputFileDescriptor);
@@ -207,7 +226,7 @@
                 ZipInputStream inputStream = buildInputStream(inputFileDescriptor);
                 restoreState.setInputStream(inputStream);
 
-                if (!seekToEntry(inputStream, configuration.getFullBackupDirectory() + name).isPresent()) {
+                if (!seekToEntry(inputStream, DEFAULT_FULL_BACKUP_DIRECTORY + name).isPresent()) {
                     IoUtils.closeQuietly(inputFileDescriptor);
                     IoUtils.closeQuietly(outputFileDescriptor);
                     return TRANSPORT_PACKAGE_REJECTED;
@@ -317,8 +336,8 @@
     }
 
     private ParcelFileDescriptor buildInputFileDescriptor() throws FileNotFoundException {
-        ContentResolver contentResolver = configuration.getContext().getContentResolver();
-        return contentResolver.openFileDescriptor(configuration.getUri(), "r");
+        ContentResolver contentResolver = context.getContentResolver();
+        return contentResolver.openFileDescriptor(requireNonNull(fileUri), "r");
     }
 
     private ZipInputStream buildInputStream(ParcelFileDescriptor inputFileDescriptor) {
diff --git a/app/src/main/java/com/stevesoltys/backup/transport/component/stub/StubBackupComponent.java b/app/src/main/java/com/stevesoltys/backup/transport/component/stub/StubBackupComponent.java
deleted file mode 100644
index 5c335a8..0000000
--- a/app/src/main/java/com/stevesoltys/backup/transport/component/stub/StubBackupComponent.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.stevesoltys.backup.transport.component.stub;
-
-import android.content.pm.PackageInfo;
-import android.os.ParcelFileDescriptor;
-import com.stevesoltys.backup.transport.component.BackupComponent;
-
-/**
- * @author Steve Soltys
- */
-public class StubBackupComponent implements BackupComponent {
-
-    @Override
-    public void cancelFullBackup() {
-
-    }
-
-    @Override
-    public int checkFullBackupSize(long size) {
-        return 0;
-    }
-
-    @Override
-    public int clearBackupData(PackageInfo packageInfo) {
-        return 0;
-    }
-
-    @Override
-    public String currentDestinationString() {
-        return null;
-    }
-
-    @Override
-    public String dataManagementLabel() {
-        return null;
-    }
-
-    @Override
-    public int finishBackup() {
-        return 0;
-    }
-
-    @Override
-    public long getBackupQuota(String packageName, boolean fullBackup) {
-        return 0;
-    }
-
-    @Override
-    public int initializeDevice() {
-        return 0;
-    }
-
-    @Override
-    public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor fileDescriptor) {
-        return 0;
-    }
-
-    @Override
-    public int performIncrementalBackup(PackageInfo targetPackage, ParcelFileDescriptor data) {
-        return 0;
-    }
-
-    @Override
-    public long requestBackupTime() {
-        return 0;
-    }
-
-    @Override
-    public long requestFullBackupTime() {
-        return 0;
-    }
-
-    @Override
-    public int sendBackupData(int numBytes) {
-        return 0;
-    }
-}
diff --git a/app/src/main/java/com/stevesoltys/backup/transport/component/stub/StubRestoreComponent.java b/app/src/main/java/com/stevesoltys/backup/transport/component/stub/StubRestoreComponent.java
deleted file mode 100644
index 56d6cfd..0000000
--- a/app/src/main/java/com/stevesoltys/backup/transport/component/stub/StubRestoreComponent.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.stevesoltys.backup.transport.component.stub;
-
-import android.content.pm.PackageInfo;
-import android.os.ParcelFileDescriptor;
-import com.stevesoltys.backup.transport.component.RestoreComponent;
-import android.app.backup.RestoreDescription;
-import android.app.backup.RestoreSet;
-
-/**
- * @author Steve Soltys
- */
-public class StubRestoreComponent implements RestoreComponent {
-
-    @Override
-    public int startRestore(long token, PackageInfo[] packages) {
-        return 0;
-    }
-
-    @Override
-    public RestoreDescription nextRestorePackage() {
-        return null;
-    }
-
-    @Override
-    public int getRestoreData(ParcelFileDescriptor outputFileDescriptor) {
-        return 0;
-    }
-
-    @Override
-    public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
-        return 0;
-    }
-
-    @Override
-    public int abortFullRestore() {
-        return 0;
-    }
-
-    @Override
-    public long getCurrentRestoreSet() {
-        return 0;
-    }
-
-    @Override
-    public void finishRestore() {
-
-    }
-
-    @Override
-    public RestoreSet[] getAvailableRestoreSets() {
-        return new RestoreSet[0];
-    }
-}