diff --git a/res/layout/swap_wifi_qr.xml b/res/layout/swap_wifi_qr.xml
index b916b0332..ae9af93b1 100644
--- a/res/layout/swap_wifi_qr.xml
+++ b/res/layout/swap_wifi_qr.xml
@@ -1,50 +1,53 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              xmlns:tools="http://schemas.android.com/tools">
+<ScrollView
+    xmlns:tools="http://schemas.android.com/tools"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="wrap_content">
 
-    <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:id="@+id/textView"
-            android:layout_gravity="center_horizontal"
-            android:layout_alignParentTop="true"
-            android:layout_alignParentLeft="true"
-            android:layout_alignParentStart="true"
-            android:text="One person needs to scan the  code, or type the URL of the  other swapper into a browser."
-            style="@style/SwapTheme.Wizard.MainText"/>
-    <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:id="@+id/wifi_qr_code"
-            tools:src="@drawable/swap_qr_example"
-            android:layout_below="@+id/textView"
-            android:layout_above="@+id/device_ip_address"/>
+    <LinearLayout android:orientation="vertical"
+                  android:gravity="center"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content">
 
-    <!--
-    <Button style="@style/SwapTheme.Wizard.OptionButton"
-            android:id="@+id/btn_not_working"
-            android:text="@string/swap_wifi_qr_not_working"
-            android:layout_alignParentBottom="true" />
-    -->
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/textView"
+                android:text="One person needs to scan the  code, or type the URL of the  other swapper into a browser."
+                style="@style/SwapTheme.Wizard.MainText"/>
 
-    <Button style="@style/SwapTheme.Wizard.OptionButton"
-            android:text="@string/open_qr_code_scanner"
-            android:layout_gravity="center"
-            android:layout_alignParentBottom="true"
-            android:id="@+id/btn_qr_scanner"/>
-    <!-- android:layout_above="@id/btn_not_working" -->
+        <ImageView
+                android:layout_width="250dp"
+                android:layout_height="250dp"
+                android:maxHeight="20dp"
+                android:id="@+id/wifi_qr_code"
+                tools:src="@drawable/swap_qr_example"/>
 
-    <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:id="@+id/device_ip_address"
-            tools:text="192.168.1.1:8888"
-            android:layout_above="@+id/btn_qr_scanner"
-            android:layout_centerHorizontal="true"
-            style="@style/SwapTheme.Wizard.LocalIpAddress"/>
+        <!--
+        <Button style="@style/SwapTheme.Wizard.OptionButton"
+                android:id="@+id/btn_not_working"
+                android:text="@string/swap_wifi_qr_not_working"
+                android:layout_alignParentBottom="true" />
+        -->
 
-</RelativeLayout>
\ No newline at end of file
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/device_ip_address"
+                tools:text="http://255.255.255.255:8888"
+                style="@style/SwapTheme.Wizard.LocalIpAddress"/>
+
+        <Button style="@style/SwapTheme.Wizard.OptionButton"
+                android:text="@string/open_qr_code_scanner"
+                android:layout_gravity="center"
+                android:id="@+id/btn_qr_scanner"/>
+
+        <Button style="@style/SwapTheme.Wizard.OptionButton"
+                android:id="@+id/btn_cancel_swap"
+                android:text="@string/cancel" />
+
+    </LinearLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/res/values/styles.xml b/res/values/styles.xml
index fa3512fe8..1d34a71d8 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -113,7 +113,7 @@
     </style>
 
     <style name="SwapTheme.Wizard.LocalIpAddress" parent="@style/SwapTheme.Wizard.Text">
-        <item name="android:textSize">32.5sp</item> <!-- 58px * 96dpi / 160dpi -->
+        <item name="android:textSize">26.5sp</item> <!-- 58px * 96dpi / 160dpi = 32.5sp (ended up making a bit smaller, because longer addresses didn't fit well) -->
         <item name="android:paddingLeft">40dp</item>
         <item name="android:paddingRight">40dp</item>
         <item name="android:paddingTop">22.5dp</item> <!-- 40px * 96dpi / 160dpi -->
diff --git a/src/org/fdroid/fdroid/FDroidApp.java b/src/org/fdroid/fdroid/FDroidApp.java
index 249e32d94..e16a5728c 100644
--- a/src/org/fdroid/fdroid/FDroidApp.java
+++ b/src/org/fdroid/fdroid/FDroidApp.java
@@ -41,13 +41,11 @@ import android.os.Messenger;
 import android.os.RemoteException;
 import android.preference.PreferenceManager;
 import android.widget.Toast;
-
 import com.nostra13.universalimageloader.cache.disc.impl.LimitedAgeDiscCache;
 import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;
 import com.nostra13.universalimageloader.core.ImageLoader;
 import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
 import com.nostra13.universalimageloader.utils.StorageUtils;
-
 import org.fdroid.fdroid.Preferences.ChangeListener;
 import org.fdroid.fdroid.compat.PRNGFixes;
 import org.fdroid.fdroid.data.AppProvider;
@@ -57,6 +55,9 @@ import org.fdroid.fdroid.localrepo.LocalRepoService;
 import org.fdroid.fdroid.net.IconDownloader;
 import org.fdroid.fdroid.net.WifiStateChangeService;
 
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
 import java.io.File;
 import java.util.Set;
 
@@ -73,6 +74,8 @@ public class FDroidApp extends Application {
     private static Messenger localRepoServiceMessenger = null;
     private static boolean localRepoServiceIsBound = false;
 
+    private static final String TAG = "org.fdroid.fdroid.FDroidApp";
+
     BluetoothAdapter bluetoothAdapter = null;
 
     public static enum Theme {
@@ -266,8 +269,7 @@ public class FDroidApp extends Application {
         if (!localRepoServiceIsBound) {
             Context app = context.getApplicationContext();
             Intent service = new Intent(app, LocalRepoService.class);
-            localRepoServiceIsBound = app.bindService(service, serviceConnection,
-                    Context.BIND_AUTO_CREATE);
+            localRepoServiceIsBound = app.bindService(service, serviceConnection, Context.BIND_AUTO_CREATE);
             if (localRepoServiceIsBound)
                 app.startService(service);
         }
@@ -285,8 +287,7 @@ public class FDroidApp extends Application {
     public static void restartLocalRepoService() {
         if (localRepoServiceMessenger != null) {
             try {
-                Message msg = Message.obtain(null,
-                        LocalRepoService.RESTART, LocalRepoService.RESTART, 0);
+                Message msg = Message.obtain(null, LocalRepoService.RESTART, LocalRepoService.RESTART, 0);
                 localRepoServiceMessenger.send(msg);
             } catch (RemoteException e) {
                 e.printStackTrace();
@@ -294,7 +295,7 @@ public class FDroidApp extends Application {
         }
     }
 
-    public static boolean isLocalRepoServiceRunnig() {
+    public static boolean isLocalRepoServiceRunning() {
         return localRepoServiceIsBound;
     }
 }
diff --git a/src/org/fdroid/fdroid/QrGenAsyncTask.java b/src/org/fdroid/fdroid/QrGenAsyncTask.java
index ebfc0fc19..e3a167e1f 100644
--- a/src/org/fdroid/fdroid/QrGenAsyncTask.java
+++ b/src/org/fdroid/fdroid/QrGenAsyncTask.java
@@ -70,6 +70,11 @@ public class QrGenAsyncTask extends AsyncTask<String, Void, Void> {
     @Override
     protected void onPostExecute(Void v) {
         ImageView qrCodeImageView = (ImageView) activity.findViewById(viewId);
-        qrCodeImageView.setImageBitmap(qrBitmap);
+
+        // If the generation takes too long for whatever reason, then this view, and indeed the entire
+        // activity may not be around any more.
+        if (qrCodeImageView != null) {
+            qrCodeImageView.setImageBitmap(qrBitmap);
+        }
     }
 }
diff --git a/src/org/fdroid/fdroid/localrepo/LocalRepoService.java b/src/org/fdroid/fdroid/localrepo/LocalRepoService.java
index 6b9152d08..a8ed9f59b 100644
--- a/src/org/fdroid/fdroid/localrepo/LocalRepoService.java
+++ b/src/org/fdroid/fdroid/localrepo/LocalRepoService.java
@@ -58,25 +58,35 @@ public class LocalRepoService extends Service {
 
     final Messenger messenger = new Messenger(new StartStopHandler(this));
 
+    /**
+     * This is most likely going to be created on the UI thread, hence all of
+     * the message handling will take place on a new thread to prevent blocking
+     * the UI.
+     */
     static class StartStopHandler extends Handler {
-        private static LocalRepoService service;
+
+        private final LocalRepoService service;
 
         public StartStopHandler(LocalRepoService service) {
-            StartStopHandler.service = service;
+            this.service = service;
         }
 
         @Override
-        public void handleMessage(Message msg) {
-            if (msg.arg1 == START) {
-                service.startNetworkServices();
-            } else if (msg.arg1 == STOP) {
-                service.stopNetworkServices();
-            } else if (msg.arg1 == RESTART) {
-                service.stopNetworkServices();
-                service.startNetworkServices();
-            } else {
-                Log.e(TAG, "unsupported msg.arg1, ignored");
-            }
+        public void handleMessage(final Message msg) {
+            new Thread() {
+                public void run() {
+                    if (msg.arg1 == START) {
+                        service.startNetworkServices();
+                    } else if (msg.arg1 == STOP) {
+                        service.stopNetworkServices();
+                    } else if (msg.arg1 == RESTART) {
+                        service.stopNetworkServices();
+                        service.startNetworkServices();
+                    } else {
+                        Log.e(TAG, "Unsupported msg.arg1 (" + msg.arg1 + "), ignored");
+                    }
+                }
+            }.start();
         }
     }
 
@@ -116,14 +126,12 @@ public class LocalRepoService extends Service {
         }
     };
 
-    @Override
-    public void onCreate() {
+    private void showNotification() {
         notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
         // launch LocalRepoActivity if the user selects this notification
         Intent intent = new Intent(this, SwapActivity.class);
         intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
+        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
         notification = new NotificationCompat.Builder(this)
                 .setContentTitle(getText(R.string.local_repo_running))
                 .setContentText(getText(R.string.touch_to_configure_local_repo))
@@ -131,6 +139,11 @@ public class LocalRepoService extends Service {
                 .setContentIntent(contentIntent)
                 .build();
         startForeground(NOTIFICATION, notification);
+    }
+
+    @Override
+    public void onCreate() {
+        showNotification();
         startNetworkServices();
         Preferences.get().registerLocalRepoBonjourListeners(localRepoBonjourChangeListener);
 
@@ -147,7 +160,12 @@ public class LocalRepoService extends Service {
 
     @Override
     public void onDestroy() {
-        stopNetworkServices();
+        new Thread() {
+            public void run() {
+                stopNetworkServices();
+            }
+        }.start();
+
         notificationManager.cancel(NOTIFICATION);
         LocalBroadcastManager.getInstance(this).unregisterReceiver(onWifiChange);
         Preferences.get().unregisterLocalRepoBonjourListeners(localRepoBonjourChangeListener);
@@ -159,6 +177,7 @@ public class LocalRepoService extends Service {
     }
 
     private void startNetworkServices() {
+        Log.d(TAG, "Starting local repo network services");
         startWebServer();
         if (Preferences.get().isLocalRepoBonjourEnabled())
             registerMDNSService();
@@ -166,8 +185,13 @@ public class LocalRepoService extends Service {
     }
 
     private void stopNetworkServices() {
+        Log.d(TAG, "Stopping local repo network services");
         Preferences.get().unregisterLocalRepoHttpsListeners(localRepoHttpsChangeListener);
+
+        Log.d(TAG, "Unregistering MDNS service...");
         unregisterMDNSService();
+
+        Log.d(TAG, "Stopping web server...");
         stopWebServer();
     }
 
diff --git a/src/org/fdroid/fdroid/views/LocalRepoActivity.java b/src/org/fdroid/fdroid/views/LocalRepoActivity.java
index 67ef20e07..0005245f3 100644
--- a/src/org/fdroid/fdroid/views/LocalRepoActivity.java
+++ b/src/org/fdroid/fdroid/views/LocalRepoActivity.java
@@ -74,7 +74,7 @@ public class LocalRepoActivity extends ActionBarActivity {
     public void onResume() {
         super.onResume();
         resetNetworkInfo();
-        setRepoSwitchChecked(FDroidApp.isLocalRepoServiceRunnig());
+        setRepoSwitchChecked(FDroidApp.isLocalRepoServiceRunning());
 
         LocalBroadcastManager.getInstance(this).registerReceiver(onWifiChange,
                 new IntentFilter(WifiStateChangeService.BROADCAST));
diff --git a/src/org/fdroid/fdroid/views/swap/SwapActivity.java b/src/org/fdroid/fdroid/views/swap/SwapActivity.java
index 3359db011..f9ba06dea 100644
--- a/src/org/fdroid/fdroid/views/swap/SwapActivity.java
+++ b/src/org/fdroid/fdroid/views/swap/SwapActivity.java
@@ -121,7 +121,7 @@ public class SwapActivity extends ActionBarActivity implements SwapProcessManage
 
         if (savedInstanceState == null) {
 
-            if (FDroidApp.isLocalRepoServiceRunnig()) {
+            if (FDroidApp.isLocalRepoServiceRunning()) {
                 onWifiQr();
             } else {
 
@@ -218,9 +218,13 @@ public class SwapActivity extends ActionBarActivity implements SwapProcessManage
     }
 
     private void startLocalRepo() {
-        if (!FDroidApp.isLocalRepoServiceRunnig()) {
+        if (!FDroidApp.isLocalRepoServiceRunning()) {
             FDroidApp.startLocalRepoService(this);
+            initLocalRepoTimer(900000); // 15 mins
         }
+    }
+
+    private void initLocalRepoTimer(long timeoutMilliseconds) {
 
         // reset the timer if viewing this Activity again
         if (shutdownLocalRepoTimer != null)
@@ -233,7 +237,19 @@ public class SwapActivity extends ActionBarActivity implements SwapProcessManage
             public void run() {
                 FDroidApp.stopLocalRepoService(SwapActivity.this);
             }
-        }, 900000); // 15 minutes
+        }, timeoutMilliseconds);
+
+    }
+
+    @Override
+    public void stopSwapping() {
+        if (FDroidApp.isLocalRepoServiceRunning()) {
+            if (shutdownLocalRepoTimer != null) {
+                shutdownLocalRepoTimer.cancel();
+            }
+            FDroidApp.stopLocalRepoService(SwapActivity.this);
+        }
+        finish();
     }
 
     class UpdateAsyncTask extends AsyncTask<Void, String, Void> {
diff --git a/src/org/fdroid/fdroid/views/swap/SwapProcessManager.java b/src/org/fdroid/fdroid/views/swap/SwapProcessManager.java
index fcf9aebc5..0153fc578 100644
--- a/src/org/fdroid/fdroid/views/swap/SwapProcessManager.java
+++ b/src/org/fdroid/fdroid/views/swap/SwapProcessManager.java
@@ -2,4 +2,5 @@ package org.fdroid.fdroid.views.swap;
 
 public interface SwapProcessManager {
     public void nextStep();
+    public void stopSwapping();
 }
diff --git a/src/org/fdroid/fdroid/views/swap/WifiQrFragment.java b/src/org/fdroid/fdroid/views/swap/WifiQrFragment.java
index 1f9b296ea..4349382aa 100644
--- a/src/org/fdroid/fdroid/views/swap/WifiQrFragment.java
+++ b/src/org/fdroid/fdroid/views/swap/WifiQrFragment.java
@@ -45,6 +45,8 @@ public class WifiQrFragment extends Fragment {
         }
     };
 
+    private SwapProcessManager swapManager;
+
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         View view = inflater.inflate(R.layout.swap_wifi_qr, container, false);
@@ -62,9 +64,22 @@ public class WifiQrFragment extends Fragment {
             }
         });
 
+        Button cancel = (Button)view.findViewById(R.id.btn_cancel_swap);
+        cancel.setOnClickListener(new Button.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                swapManager.stopSwapping();
+            }
+        });
         return view;
     }
 
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        swapManager = (SwapProcessManager)activity;
+    }
+
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent intent) {
         IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);