diff --git a/briar-android/src/net/sf/briar/android/AndroidModule.java b/briar-android/src/net/sf/briar/android/AndroidModule.java
index 83ec34737014019708dcf2a0e0dcbeea57c9a106..d379f5086cc32b26583e3db7571a735aa3206452 100644
--- a/briar-android/src/net/sf/briar/android/AndroidModule.java
+++ b/briar-android/src/net/sf/briar/android/AndroidModule.java
@@ -1,5 +1,6 @@
 package net.sf.briar.android;
 
+import net.sf.briar.android.invitation.AddContactActivity;
 import net.sf.briar.api.android.AndroidExecutor;
 import net.sf.briar.api.android.BundleEncrypter;
 import net.sf.briar.api.android.ReferenceManager;
@@ -16,5 +17,6 @@ public class AndroidModule extends AbstractModule {
 			Singleton.class);
 		bind(ReferenceManager.class).to(ReferenceManagerImpl.class).in(
 				Singleton.class);
+		requestStaticInjection(AddContactActivity.class);
 	}
 }
diff --git a/briar-android/src/net/sf/briar/android/BundleEncrypterImpl.java b/briar-android/src/net/sf/briar/android/BundleEncrypterImpl.java
index ce8f9912d75cdb9dd70330b4c6fbbebb9d719b2e..68305ffe6ce025510f8e58c422674f633ecfbf32 100644
--- a/briar-android/src/net/sf/briar/android/BundleEncrypterImpl.java
+++ b/briar-android/src/net/sf/briar/android/BundleEncrypterImpl.java
@@ -1,10 +1,12 @@
 package net.sf.briar.android;
 
+import static java.util.logging.Level.INFO;
 import static javax.crypto.Cipher.DECRYPT_MODE;
 import static javax.crypto.Cipher.ENCRYPT_MODE;
 
 import java.security.GeneralSecurityException;
 import java.security.SecureRandom;
+import java.util.logging.Logger;
 
 import net.sf.briar.api.android.BundleEncrypter;
 import net.sf.briar.api.crypto.AuthenticatedCipher;
@@ -19,6 +21,9 @@ import com.google.inject.Inject;
 // This class is not thread-safe
 class BundleEncrypterImpl implements BundleEncrypter {
 
+	private static final Logger LOG =
+			Logger.getLogger(BundleEncrypterImpl.class.getName());
+
 	private final AuthenticatedCipher cipher;
 	private final SecureRandom random;
 	private final ErasableKey key;
@@ -40,7 +45,11 @@ class BundleEncrypterImpl implements BundleEncrypter {
 		b.writeToParcel(p, 0);
 		byte[] plaintext = p.marshall();
 		p.recycle();
-		// Encrypt the byte array using the storage key and a random IV
+		if(LOG.isLoggable(INFO)) {
+			LOG.info("Marshalled " + b.size() + " mappings, "
+					+ plaintext.length + " plaintext bytes");
+		}
+		// Encrypt the byte array using a random IV
 		byte[] iv = new byte[blockSize];
 		random.nextBytes(iv);
 		byte[] ciphertext = new byte[plaintext.length + macLength];
@@ -66,7 +75,7 @@ class BundleEncrypterImpl implements BundleEncrypter {
 		byte[] ciphertext = b.getByteArray("net.sf.briar.CIPHERTEXT");
 		if(ciphertext == null) throw new IllegalArgumentException();
 		if(ciphertext.length < macLength) throw new IllegalArgumentException();
-		// Decrypt the ciphertext using the storage key and the IV
+		// Decrypt the ciphertext using the IV
 		byte[] plaintext = new byte[ciphertext.length - macLength];
 		try {
 			cipher.init(DECRYPT_MODE, key, iv, null);
@@ -78,12 +87,14 @@ class BundleEncrypterImpl implements BundleEncrypter {
 		Parcel p = Parcel.obtain();
 		p.unmarshall(plaintext, 0, plaintext.length);
 		ByteUtils.erase(plaintext);
-		// Replace the IV and the ciphertext with the plaintext contents
-		b.remove("net.sf.briar.IV");
-		b.remove("net.sf.briar.CIPHERTEXT");
+		// Restore the plaintext contents
 		p.setDataPosition(0);
 		b.readFromParcel(p);
 		p.recycle();
+		if(LOG.isLoggable(INFO)) {
+			LOG.info("Unmarshalled " + (b.size() - 2) + " mappings, "
+					+ plaintext.length + " plaintext bytes");
+		}
 		return true;
 	}
 }
diff --git a/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java b/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java
index 5de5df339ecced46fadd2d55addad3bd1c380e71..4b25d2a8949507fde50c1656a256a74ca5f5e8fd 100644
--- a/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java
+++ b/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java
@@ -19,6 +19,7 @@ import roboguice.activity.RoboActivity;
 import android.os.Bundle;
 
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 
 public class AddContactActivity extends RoboActivity
 implements InvitationListener {
@@ -26,12 +27,17 @@ implements InvitationListener {
 	private static final Logger LOG =
 			Logger.getLogger(AddContactActivity.class.getName());
 
+	// This allows us to access bundleEncrypter before calling super.onCreate()
+	@Inject private static Provider<BundleEncrypter> bundleEncrypterProvider;
+
+	private final BundleEncrypter bundleEncrypter =
+			bundleEncrypterProvider.get();
+
 	@Inject private CryptoComponent crypto;
 	@Inject private DatabaseComponent db;
 	@Inject @DatabaseExecutor private Executor dbExecutor;
 	@Inject private InvitationTaskFactory invitationTaskFactory;
 	@Inject private ReferenceManager referenceManager;
-	@Inject private BundleEncrypter bundleEncrypter;
 
 	// All of the following must be accessed on the UI thread
 	private AddContactView view = null;
@@ -47,13 +53,13 @@ implements InvitationListener {
 
 	@Override
 	public void onCreate(Bundle state) {
-		super.onCreate(state);
-		if(state != null && !bundleEncrypter.decrypt(state)) state = null;
-		if(state == null) {
-			// This is a new activity
+		if(state == null || !bundleEncrypter.decrypt(state)) {
+			// This is a new activity or the process has restarted
+			super.onCreate(null);
 			setView(new NetworkSetupView(this));
 		} else {
 			// Restore the activity's state
+			super.onCreate(state);
 			networkName = state.getString("net.sf.briar.NETWORK_NAME");
 			useBluetooth = state.getBoolean("net.sf.briar.USE_BLUETOOTH");
 			taskHandle = state.getLong("net.sf.briar.TASK_HANDLE", -1);
@@ -114,6 +120,12 @@ implements InvitationListener {
 		}
 	}
 
+	@Override
+	public void onRestoreInstanceState(Bundle state) {
+		if(bundleEncrypter.decrypt(state))
+			super.onRestoreInstanceState(state);
+	}
+
 	@Override
 	public void onResume() {
 		super.onResume();
@@ -123,16 +135,14 @@ implements InvitationListener {
 	@Override
 	public void onSaveInstanceState(Bundle state) {
 		super.onSaveInstanceState(state);
-		Bundle b = new Bundle();
-		b.putString("net.sf.briar.NETWORK_NAME", networkName);
-		b.putBoolean("net.sf.briar.USE_BLUETOOTH", useBluetooth);
-		b.putInt("net.sf.briar.LOCAL_CODE", localInvitationCode);
-		b.putInt("net.sf.briar.REMOTE_CODE", remoteInvitationCode);
-		b.putBoolean("net.sf.briar.FAILED", connectionFailed);
-		b.putBoolean("net.sf.briar.MATCHED", localMatched && remoteMatched);
-		if(task != null) b.putLong("net.sf.briar.TASK_HANDLE", taskHandle);
-		bundleEncrypter.encrypt(b);
-		state.putAll(b);
+		state.putString("net.sf.briar.NETWORK_NAME", networkName);
+		state.putBoolean("net.sf.briar.USE_BLUETOOTH", useBluetooth);
+		state.putInt("net.sf.briar.LOCAL_CODE", localInvitationCode);
+		state.putInt("net.sf.briar.REMOTE_CODE", remoteInvitationCode);
+		state.putBoolean("net.sf.briar.FAILED", connectionFailed);
+		state.putBoolean("net.sf.briar.MATCHED", localMatched && remoteMatched);
+		if(task != null) state.putLong("net.sf.briar.TASK_HANDLE", taskHandle);
+		bundleEncrypter.encrypt(state);
 	}
 
 	@Override