diff --git a/briar-android/artwork/bluetooth.svg b/briar-android/artwork/bluetooth.svg
new file mode 100644
index 0000000000000000000000000000000000000000..951fa966c154b7db67e7c34fe53f8203532e2e96
--- /dev/null
+++ b/briar-android/artwork/bluetooth.svg
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="140.89767mm"
+   height="49.528343mm"
+   viewBox="0 0 499.24373 175.49413"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="bluetooth.svg"
+   inkscape:export-filename="bluetooth.png"
+   inkscape:export-xdpi="194.87476"
+   inkscape:export-ydpi="194.87476">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.98994949"
+     inkscape:cx="435.00934"
+     inkscape:cy="91.353462"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1920"
+     inkscape:window-height="1012"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-72.369616,-444.3511)">
+    <path
+       style="fill:#000000"
+       d="m 532.17899,615.51093 -4.32657,-4.3343 -7.06956,-2.42737 c -3.88825,-1.33505 -8.72285,-2.99587 -10.74354,-3.6907 l -3.674,-1.26333 3.524,-0.1726 c 8.24183,-0.40367 12.98778,-4.00671 14.33634,-10.88389 0.79628,-4.06078 1.12887,-17.29805 0.83016,-33.04122 -0.15338,-8.08375 -0.16617,-15.41641 -0.0284,-16.29481 0.13775,-0.8784 0.53527,-2.42011 0.88339,-3.42602 1.22247,-3.53243 0.33996,-11.90828 -1.8577,-17.63146 -0.34848,-0.9075 -1.93434,-4.215 -3.52415,-7.35 -4.15849,-8.2003 -4.50458,-8.94188 -4.89292,-10.4841 -0.45865,-1.82145 -0.21161,-5.43531 0.4625,-6.7659 0.66625,-1.31505 2.15695,-2.91616 3.24622,-3.48662 1.29885,-0.68024 2.61568,0.12202 4.6864,2.85512 3.42153,4.51599 14.00135,19.44095 15.73191,22.19301 3.74551,5.95636 5.95558,11.16496 7.9722,18.78849 0.6547,2.475 1.88525,6.9975 2.73456,10.05 0.84931,3.0525 2.71404,10.15792 4.14385,15.78983 l 2.59964,10.23983 4.65,5.19319 c 2.5575,2.85626 5.7975,6.46371 7.2,8.01657 1.4025,1.55286 2.55,2.97543 2.55,3.16127 0,0.33546 -34.49955,29.29931 -34.89913,29.29931 -0.11475,0 -2.15559,-1.95044 -4.5352,-4.3343 z m -93.86507,-16.38777 c -1.25762,-0.62844 -2.20557,-1.3788 -2.91402,-2.30663 -2.08931,-2.73629 -1.95034,2.36868 -1.86433,-68.48249 l 0.0777,-64.03881 0.66066,-1.23494 c 1.0152,-1.89767 1.99201,-2.91087 3.73952,-3.87887 l 1.59982,-0.88619 37.78387,-0.0796 c 42.45592,-0.0894 39.40239,-0.2483 42.11646,2.19188 0.87544,0.78709 1.75715,1.95946 2.18393,2.90385 0.71264,1.57698 0.71613,1.63839 0.80561,14.20405 l 0.0899,12.62022 -1.79817,-0.13007 c -1.42577,-0.10313 -2.08143,0.007 -3.16601,0.5321 -2.01294,0.97445 -3.93993,2.89871 -5.11476,5.10753 l -1.03717,1.95 -0.007,-12.825 -0.007,-12.825 -33.6,0 -33.6,0 0,51.3 0,51.3 33.59873,0 33.59874,0 0.0763,-34.425 c 0.073,-32.96021 0.0982,-34.36117 0.59098,-32.925 0.28309,0.825 1.80562,3.9975 3.3834,7.05 5.49252,10.62624 5.40494,9.86009 5.39597,47.20335 -0.007,27.62122 -0.12358,29.95084 -1.66204,33.10906 -1.07144,2.19949 -2.71143,3.71042 -5.05823,4.66019 l -1.67381,0.6774 -36.1677,0.0797 -36.16769,0.0797 -1.864,-0.93145 z m 42.39939,-5.03813 c 2.87119,-1.30885 4.45771,-3.6784 4.43003,-6.61652 -0.0388,-4.11587 -3.1088,-7.22328 -7.1364,-7.22328 -2.11956,0 -3.56727,0.60889 -5.16364,2.17177 -2.24518,2.19807 -2.75398,5.43897 -1.30101,8.28704 0.71312,1.39782 2.52137,3.00905 3.96214,3.53045 1.49707,0.54176 3.84003,0.47454 5.20888,-0.14946 z"
+       id="path4201"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="scsscssscssssscssssscssssscsscsscsssscscscccccccccscscsscccccsssssss" />
+    <path
+       style="fill:#000000"
+       d="m 111.80395,615.51093 4.32657,-4.3343 7.06956,-2.42737 c 3.88825,-1.33505 8.72285,-2.99587 10.74354,-3.6907 l 3.674,-1.26333 -3.524,-0.1726 c -8.24183,-0.40367 -12.98778,-4.00671 -14.33634,-10.88389 -0.79628,-4.06078 -1.12887,-17.29805 -0.83016,-33.04122 0.15338,-8.08375 0.16617,-15.41641 0.0284,-16.29481 -0.13775,-0.8784 -0.53527,-2.42011 -0.88339,-3.42602 -1.22247,-3.53243 -0.33996,-11.90828 1.8577,-17.63146 0.34848,-0.9075 1.93434,-4.215 3.52415,-7.35 4.15849,-8.2003 4.50458,-8.94188 4.89292,-10.4841 0.45865,-1.82145 0.21161,-5.43531 -0.4625,-6.7659 -0.66625,-1.31505 -2.15695,-2.91616 -3.24622,-3.48662 -1.29885,-0.68024 -2.61568,0.12202 -4.6864,2.85512 -3.42153,4.51599 -14.00135,19.44095 -15.73191,22.19301 -3.74551,5.95636 -5.955584,11.16496 -7.972204,18.78849 -0.6547,2.475 -1.88525,6.9975 -2.73456,10.05 -0.84931,3.0525 -2.71404,10.15792 -4.14385,15.78983 l -2.59964,10.23983 -4.65,5.19319 c -2.5575,2.85626 -5.7975,6.46371 -7.2,8.01657 -1.4025,1.55286 -2.55,2.97543 -2.55,3.16127 0,0.33546 34.499554,29.29931 34.899134,29.29931 0.11475,0 2.15559,-1.95044 4.53519,-4.3343 z m 93.86506,-16.38777 c 1.25762,-0.62844 2.20557,-1.3788 2.91402,-2.30663 2.08931,-2.73629 1.95034,2.36868 1.86433,-68.48249 l -0.0777,-64.03881 -0.66066,-1.23494 c -1.0152,-1.89767 -1.99201,-2.91087 -3.73952,-3.87887 l -1.59982,-0.88619 -37.78386,-0.0796 c -42.45592,-0.0894 -39.40239,-0.2483 -42.11646,2.19188 -0.87544,0.78709 -1.75715,1.95946 -2.18393,2.90385 -0.71264,1.57698 -0.71613,1.63839 -0.80561,14.20405 l -0.0899,12.62022 1.79817,-0.13007 c 1.42577,-0.10313 2.08143,0.007 3.16601,0.5321 2.01294,0.97445 3.93993,2.89871 5.11476,5.10753 l 1.03717,1.95 0.007,-12.825 0.007,-12.825 33.6,0 33.59999,0 0,51.3 0,51.3 -33.59872,0 -33.59874,0 -0.0763,-34.425 c -0.073,-32.96021 -0.0982,-34.36117 -0.59098,-32.925 -0.28309,0.825 -1.80562,3.9975 -3.3834,7.05 -5.49252,10.62624 -5.40494,9.86009 -5.39597,47.20335 0.007,27.62122 0.12358,29.95084 1.66204,33.10906 1.07144,2.19949 2.71143,3.71042 5.05823,4.66019 l 1.67381,0.6774 36.1677,0.0797 36.16768,0.0797 1.864,-0.93145 z m -42.39938,-5.03813 c -2.87119,-1.30885 -4.45771,-3.6784 -4.43003,-6.61652 0.0388,-4.11587 3.1088,-7.22328 7.1364,-7.22328 2.11956,0 3.56727,0.60889 5.16364,2.17177 2.24518,2.19807 2.75398,5.43897 1.30101,8.28704 -0.71312,1.39782 -2.52137,3.00905 -3.96214,3.53045 -1.49707,0.54176 -3.84003,0.47454 -5.20888,-0.14946 z"
+       id="path4201-1"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccsscssscssssscssssscsssscccsscsscsssscscscccccccccscscsscccccsssssss" />
+    <g
+       id="g4838"
+       transform="matrix(0.08166146,0,0,0.08166146,285.28364,535.81196)">
+      <rect
+         id="rect4270"
+         width="640"
+         height="976"
+         ry="291"
+         style="fill:#0a3d91"
+         x="129.51247"
+         y="-189.58334" />
+      <path
+         id="path4272"
+         d="m 286.51248,140.41666 305,307.00003 -147,178 0,-636.000027 147,169.999997 -305,299.00003"
+         style="fill:none;stroke:#ffffff;stroke-width:53"
+         inkscape:connector-curvature="0" />
+    </g>
+    <path
+       style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#0a3d91;stroke-width:7.55;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:7.55,22.65;stroke-dashoffset:0;stroke-opacity:1"
+       d="m 219.05071,474.19795 c 70.76376,46.48067 139.93534,38.03285 208.24431,-0.1739"
+       id="path4844"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+  </g>
+</svg>
diff --git a/briar-android/res/drawable/bluetooth.png b/briar-android/res/drawable/bluetooth.png
new file mode 100644
index 0000000000000000000000000000000000000000..f99091e6726ba462096b3b4abe568e86e874ece6
Binary files /dev/null and b/briar-android/res/drawable/bluetooth.png differ
diff --git a/briar-android/res/layout/invitation_bluetooth_confirmation_code.xml b/briar-android/res/layout/invitation_bluetooth_confirmation_code.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bf0d3ee68aefc16e31c2130c14d1aefe27798a9d
--- /dev/null
+++ b/briar-android/res/layout/invitation_bluetooth_confirmation_code.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <RelativeLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="@dimen/margin_activity_vertical"
+        android:paddingEnd="@dimen/margin_activity_horizontal"
+        android:paddingRight="@dimen/margin_activity_horizontal"
+        android:paddingStart="@dimen/margin_activity_horizontal"
+        android:paddingLeft="@dimen/margin_activity_horizontal"
+        android:paddingTop="@dimen/margin_activity_vertical">
+
+        <TextView
+            android:id="@+id/stepView"
+            style="@style/BriarTextBody"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end"
+            android:padding="@dimen/margin_medium"
+            tools:text="Step 3/3"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentEnd="true"/>
+
+        <TextView
+            android:id="@+id/connectedView"
+            style="@style/BriarTextTitle"
+            android:textSize="@dimen/text_size_large"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/connected_to_contact"
+            android:padding="@dimen/margin_medium"
+            android:layout_below="@+id/stepView"
+            android:layout_centerHorizontal="true"
+            android:drawableLeft="@drawable/navigation_accept"
+            android:drawableStart="@drawable/navigation_accept"
+            android:gravity="center_vertical"/>
+
+        <TextView
+            android:id="@+id/yourConfirmationCodeView"
+            style="@style/BriarTextBody"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/your_confirmation_code"
+            android:padding="@dimen/margin_medium"
+            android:layout_below="@+id/connectedView"
+            android:layout_centerHorizontal="true"/>
+
+        <TextView
+            android:id="@+id/codeView"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="@dimen/margin_medium"
+            android:textSize="50sp"
+            android:layout_below="@+id/yourConfirmationCodeView"
+            android:layout_centerHorizontal="true"
+            tools:text="1337"/>
+
+        <TextView
+            android:id="@+id/waitingView"
+            style="@style/BriarTextBody"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/searching_format"
+            android:layout_gravity="center_horizontal"
+            android:padding="@dimen/margin_medium"
+            android:layout_below="@+id/codeView"
+            android:layout_centerHorizontal="true"
+            android:visibility="gone"
+            android:gravity="center_horizontal"/>
+
+        <ProgressBar
+            android:id="@+id/progressBar"
+            style="?android:attr/progressBarStyleLarge"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:indeterminate="true"
+            android:layout_below="@+id/waitingView"
+            android:layout_centerHorizontal="true"
+            android:visibility="gone"/>
+
+        <TextView
+            android:id="@+id/enterCodeTextView"
+            style="@style/BriarTextBody"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/enter_confirmation_code"
+            android:layout_gravity="center_horizontal"
+            android:padding="@dimen/margin_medium"
+            android:layout_below="@+id/codeView"
+            android:layout_centerHorizontal="true"/>
+
+        <include
+            android:id="@+id/codeEntryView"
+            layout="@layout/view_code_entry"
+            android:layout_below="@+id/enterCodeTextView"
+            android:layout_centerHorizontal="true"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/margin_medium"/>
+
+        <Button
+            android:id="@+id/continueButton"
+            style="@style/BriarButton.Default"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/continue_button"
+            android:layout_gravity="center_horizontal"
+            android:enabled="false"
+            android:layout_below="@+id/codeEntryView"
+            android:layout_centerHorizontal="true"
+            android:layout_margin="@dimen/margin_medium"/>
+
+    </RelativeLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/briar-android/res/layout/invitation_bluetooth_invitation_code.xml b/briar-android/res/layout/invitation_bluetooth_invitation_code.xml
new file mode 100644
index 0000000000000000000000000000000000000000..875a58d08aefd46951721cce332e8671fe33e792
--- /dev/null
+++ b/briar-android/res/layout/invitation_bluetooth_invitation_code.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <RelativeLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="@dimen/margin_activity_vertical"
+        android:paddingEnd="@dimen/margin_activity_horizontal"
+        android:paddingRight="@dimen/margin_activity_horizontal"
+        android:paddingStart="@dimen/margin_activity_horizontal"
+        android:paddingLeft="@dimen/margin_activity_horizontal"
+        android:paddingTop="@dimen/margin_activity_vertical">
+
+        <TextView
+            android:id="@+id/stepView"
+            style="@style/BriarTextBody"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end"
+            android:layout_marginTop="@dimen/margin_medium"
+            tools:text="Step 2/3"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentEnd="true"/>
+
+        <TextView
+            android:id="@+id/yourCodeView"
+            style="@style/BriarTextBody"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/your_invitation_code"
+            android:layout_marginTop="@dimen/margin_medium"
+            android:layout_below="@+id/stepView"
+            android:layout_centerHorizontal="true"/>
+
+        <TextView
+            android:id="@+id/codeView"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/margin_medium"
+            android:textSize="50sp"
+            android:layout_below="@+id/yourCodeView"
+            android:layout_centerHorizontal="true"
+            tools:text="1337"/>
+
+        <TextView
+            android:id="@+id/waitingView"
+            style="@style/BriarTextBody"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/searching_format"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginTop="@dimen/margin_medium"
+            android:layout_below="@+id/codeView"
+            android:layout_centerHorizontal="true"
+            android:visibility="gone"
+            android:gravity="center_horizontal"/>
+
+        <ProgressBar
+            android:id="@+id/progressBar"
+            style="?android:attr/progressBarStyleLarge"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:indeterminate="true"
+            android:layout_below="@+id/waitingView"
+            android:layout_centerHorizontal="true"
+            android:visibility="gone"/>
+
+        <TextView
+            android:id="@+id/enterCodeTextView"
+            style="@style/BriarTextBody"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/enter_invitation_code"
+            android:layout_gravity="center_horizontal"
+            android:padding="@dimen/margin_medium"
+            android:layout_below="@+id/codeView"
+            android:layout_centerHorizontal="true"/>
+
+        <include
+            android:id="@+id/codeEntryView"
+            layout="@layout/view_code_entry"
+            android:layout_below="@+id/enterCodeTextView"
+            android:layout_centerHorizontal="true"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/margin_medium"/>
+
+        <Button
+            android:id="@+id/continueButton"
+            style="@style/BriarButton.Default"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/continue_button"
+            android:layout_gravity="center_horizontal"
+            android:enabled="false"
+            android:layout_below="@+id/codeEntryView"
+            android:layout_centerHorizontal="true"
+            android:layout_margin="@dimen/margin_medium"/>
+
+    </RelativeLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/briar-android/res/layout/invitation_bluetooth_start.xml b/briar-android/res/layout/invitation_bluetooth_start.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9198f7537fba193244d028c2c5c68d7e0f5e6f3d
--- /dev/null
+++ b/briar-android/res/layout/invitation_bluetooth_start.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:tools="http://schemas.android.com/tools"
+	android:layout_width="match_parent"
+	android:layout_height="match_parent">
+
+	<LinearLayout
+		android:orientation="vertical"
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		android:paddingBottom="@dimen/margin_activity_vertical"
+		android:paddingEnd="@dimen/margin_activity_horizontal"
+		android:paddingRight="@dimen/margin_activity_horizontal"
+		android:paddingStart="@dimen/margin_activity_horizontal"
+		android:paddingLeft="@dimen/margin_activity_horizontal"
+		android:paddingTop="@dimen/margin_activity_vertical">
+
+		<TextView
+			android:id="@+id/stepView"
+			style="@style/BriarTextBody"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_gravity="end"
+			tools:text="Step 1/3"/>
+
+		<TextView
+			android:id="@+id/yourNicknameView"
+			style="@style/BriarTextBody"
+			android:layout_width="match_parent"
+			android:layout_height="wrap_content"
+			android:text="@string/your_nickname"
+			android:layout_marginTop="@dimen/margin_medium"/>
+
+		<Spinner
+			android:layout_width="match_parent"
+			android:layout_height="wrap_content"
+			android:id="@+id/spinner"
+			android:spinnerMode="dropdown"
+			android:layout_marginTop="@dimen/margin_medium"/>
+
+		<ImageView
+			android:layout_width="match_parent"
+			android:layout_height="wrap_content"
+			android:id="@+id/imageView"
+			android:src="@drawable/bluetooth"
+			android:scaleType="fitCenter"
+			android:adjustViewBounds="true"
+			android:layout_marginTop="@dimen/margin_medium"/>
+
+		<TextView
+			android:id="@+id/faceToFaceView"
+			style="@style/BriarTextBody"
+			android:layout_width="match_parent"
+			android:layout_height="wrap_content"
+			android:text="@string/face_to_face"
+			android:layout_marginTop="@dimen/margin_medium"/>
+
+		<Button
+			android:id="@+id/continueButton"
+			style="@style/BriarButton.Default"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:text="@string/continue_button"
+			android:layout_gravity="center_horizontal"
+			android:layout_marginTop="@dimen/margin_medium"/>
+	</LinearLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/briar-android/res/layout/invitation_error.xml b/briar-android/res/layout/invitation_error.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e1c94c393620793a72c963a3cc8300e818119866
--- /dev/null
+++ b/briar-android/res/layout/invitation_error.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/margin_activity_vertical"
+    android:paddingEnd="@dimen/margin_activity_horizontal"
+    android:paddingStart="@dimen/margin_activity_horizontal"
+    android:paddingTop="@dimen/margin_activity_vertical">
+
+    <TextView
+        android:id="@+id/errorTextView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/connection_failed"
+        android:layout_gravity="center_horizontal"
+        android:textSize="@dimen/text_size_large"
+        android:drawableStart="@drawable/alerts_and_states_error"
+        android:drawableLeft="@drawable/alerts_and_states_error"
+        android:gravity="center_vertical"
+        android:padding="@dimen/margin_medium"/>
+
+    <TextView
+        android:id="@+id/explanationTextView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/interfering"
+        android:layout_gravity="center_horizontal"
+        android:padding="@dimen/margin_medium"/>
+
+    <Button
+        android:id="@+id/tryAgainButton"
+        style="@style/BriarButton.Default"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/try_again_button"
+        android:layout_gravity="center_horizontal"
+        android:layout_margin="@dimen/margin_medium"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/briar-android/res/layout/view_code_entry.xml b/briar-android/res/layout/view_code_entry.xml
new file mode 100644
index 0000000000000000000000000000000000000000..018915876e8e147e3a5a04fb6aac062e5b74a13f
--- /dev/null
+++ b/briar-android/res/layout/view_code_entry.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<EditText
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/codeEntryView"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:inputType="number"
+    android:layout_gravity="center_horizontal"
+    android:textSize="@dimen/text_size_xlarge"
+    android:ems="4"
+    android:maxLines="1"
+    android:maxLength="6"
+    android:layout_margin="@dimen/margin_medium"
+    android:imeOptions="actionGo"
+    tools:text="123456"/>
\ No newline at end of file
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 6532d77d8a105c55ee96a9684282b88ab136f3fe..1df0b4897ad53800926576f5c861e6c86ecbc1f1 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -36,12 +36,12 @@
     <string name="contact_list_title">Contacts</string>
     <string name="no_contacts">No contacts</string>
     <string name="add_contact_title">Add a Contact</string>
-    <string name="your_nickname">Your nickname: </string>
-    <string name="face_to_face">For security reasons you must be face-to-face with the person you want to add as a contact.\n\nThis will prevent anyone from impersonating you or reading your messages in future.</string>
+    <string name="your_nickname">Please select the identity you want to use:</string>
+    <string name="face_to_face">You must be face-to-face with the person you want to add as a contact. This will prevent anyone from impersonating you or reading your messages in future.</string>
     <string name="continue_button">Continue</string>
     <string name="your_invitation_code">Your invitation code is</string>
     <string name="enter_invitation_code">Please enter your contact\'s invitation code:</string>
-    <string name="searching_format">Searching for %06d\u2026</string>
+    <string name="searching_format">Searching for contact with invitation code %06d\u2026</string>
     <string name="connection_failed">Connection failed</string>
     <string name="could_not_find_contact">Briar could not find your contact nearby</string>
     <string name="try_again_button">Try Again</string>
@@ -110,8 +110,9 @@
     <string name="notify_sound_setting_default">Default ringtone</string>
     <string name="notify_sound_setting_disabled">None</string>
     <string name="choose_ringtone_title">Choose ringtone</string>
+    <string name="step">Step %1$d/%2$d</string>
 
     <!-- Dialogs -->
     <string name="dialog_title_lost_password">Lost password</string>
     <string name="dialog_message_lost_password">Password recovery is not possible. Do you wish to delete your user, all contacts, and re-register ?</string>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
index eb0a52e9da0649d590fc7c526e52788d2a8fb498..ab318363be0286c52ac208e57f751e183f3ed78e 100644
--- a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
+++ b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
@@ -1,13 +1,9 @@
 package org.briarproject.android.invitation;
 
-import static android.widget.Toast.LENGTH_LONG;
-import static java.util.logging.Level.INFO;
-import static java.util.logging.Level.WARNING;
-
-import java.util.Collection;
-import java.util.logging.Logger;
-
-import javax.inject.Inject;
+import android.bluetooth.BluetoothAdapter;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.Toast;
 
 import org.briarproject.R;
 import org.briarproject.android.BriarActivity;
@@ -24,10 +20,17 @@ import org.briarproject.api.invitation.InvitationState;
 import org.briarproject.api.invitation.InvitationTask;
 import org.briarproject.api.invitation.InvitationTaskFactory;
 
-import android.bluetooth.BluetoothAdapter;
-import android.content.Intent;
-import android.os.Bundle;
-import android.widget.Toast;
+import java.util.Collection;
+import java.util.logging.Logger;
+
+import javax.inject.Inject;
+
+import static android.widget.Toast.LENGTH_LONG;
+import static java.util.logging.Level.INFO;
+import static java.util.logging.Level.WARNING;
+import static org.briarproject.android.invitation.ConfirmationCodeView.ConfirmationState.CONNECTED;
+import static org.briarproject.android.invitation.ConfirmationCodeView.ConfirmationState.WAIT_FOR_CONTACT;
+import static org.briarproject.android.invitation.ConfirmationCodeView.ConfirmationState.DETAILS;
 
 public class AddContactActivity extends BriarActivity
 implements InvitationListener {
@@ -86,9 +89,10 @@ implements InvitationListener {
 				} else if (remoteInvitationCode == -1) {
 					setView(new InvitationCodeView(this));
 				} else if (connectionFailed) {
-					setView(new ConnectionFailedView(this));
+					setView(new ErrorView(this, R.string.connection_failed,
+							R.string.could_not_find_contact));
 				} else if (contactName == null) {
-					setView(new CodesDoNotMatchView(this));
+					setView(new ErrorView(this, R.string.codes_do_not_match, R.string.interfering));
 				} else {
 					showToastAndFinish();
 					return;
@@ -113,24 +117,25 @@ implements InvitationListener {
 				} else if (remoteInvitationCode == -1) {
 					setView(new InvitationCodeView(this));
 				} else if (connectionFailed) {
-					setView(new ConnectionFailedView(this));
+					setView(new ErrorView(AddContactActivity.this, R.string.connection_failed,
+							R.string.could_not_find_contact));
 				} else if (connected && localConfirmationCode == -1) {
-					setView(new ConnectedView(this));
+					setView(new ConfirmationCodeView(this, CONNECTED));
 				} else if (localConfirmationCode == -1) {
-					setView(new ConnectionView(this));
+					setView(new InvitationCodeView(this, true));
 				} else if (!localCompared) {
 					setView(new ConfirmationCodeView(this));
 				} else if (!remoteCompared) {
-					setView(new WaitForContactView(this));
+					setView(new ConfirmationCodeView(this, WAIT_FOR_CONTACT));
 				} else if (localMatched && remoteMatched) {
 					if (contactName == null) {
-						setView(new ContactDetailsView(this));
+						setView(new ConfirmationCodeView(this, DETAILS));
 					} else {
 						showToastAndFinish();
 						return;
 					}
 				} else {
-					setView(new CodesDoNotMatchView(this));
+					setView(new ErrorView(this, R.string.codes_do_not_match, R.string.interfering));
 				}
 			}
 		}
@@ -276,7 +281,10 @@ implements InvitationListener {
 		if (localAuthorId == null) throw new IllegalStateException();
 		if (localInvitationCode == -1) throw new IllegalStateException();
 		remoteInvitationCode = code;
-		setView(new ConnectionView(this));
+
+		// change UI to show a progress indicator
+		setView(new InvitationCodeView(this, true));
+
 		task = invitationTaskFactory.createTask(localAuthorId,
 				localInvitationCode, code, enableBluetooth);
 		taskHandle = referenceManager.putReference(task, InvitationTask.class);
@@ -295,13 +303,14 @@ implements InvitationListener {
 		localCompared = true;
 		if (code == remoteConfirmationCode) {
 			localMatched = true;
-			if (remoteMatched) setView(new ContactDetailsView(this));
-			else if (remoteCompared) setView(new CodesDoNotMatchView(this));
-			else setView(new WaitForContactView(this));
+			if (remoteMatched) setView(new ConfirmationCodeView(this, DETAILS));
+			else if (remoteCompared) setView(new ErrorView(this, R.string.codes_do_not_match,
+					R.string.interfering));
+			else setView(new ConfirmationCodeView(this, WAIT_FOR_CONTACT));
 			task.localConfirmationSucceeded();
 		} else {
 			localMatched = false;
-			setView(new CodesDoNotMatchView(this));
+			setView(new ErrorView(this, R.string.codes_do_not_match, R.string.interfering));
 			task.localConfirmationFailed();
 		}
 	}
@@ -314,7 +323,7 @@ implements InvitationListener {
 		runOnUiThread(new Runnable() {
 			public void run() {
 				connected = true;
-				setView(new ConnectedView(AddContactActivity.this));
+				setView(new ConfirmationCodeView(AddContactActivity.this, CONNECTED));
 			}
 		});
 	}
@@ -323,7 +332,8 @@ implements InvitationListener {
 		runOnUiThread(new Runnable() {
 			public void run() {
 				connectionFailed = true;
-				setView(new ConnectionFailedView(AddContactActivity.this));
+				setView(new ErrorView(AddContactActivity.this, R.string.connection_failed,
+						R.string.could_not_find_contact));
 			}
 		});
 	}
@@ -343,7 +353,8 @@ implements InvitationListener {
 		runOnUiThread(new Runnable() {
 			public void run() {
 				connectionFailed = true;
-				setView(new ConnectionFailedView(AddContactActivity.this));
+				setView(new ErrorView(AddContactActivity.this, R.string.connection_failed,
+						R.string.could_not_find_contact));
 			}
 		});
 	}
@@ -354,7 +365,7 @@ implements InvitationListener {
 				remoteCompared = true;
 				remoteMatched = true;
 				if (localMatched)
-					setView(new ContactDetailsView(AddContactActivity.this));
+					setView(new ConfirmationCodeView(AddContactActivity.this, DETAILS));
 			}
 		});
 	}
@@ -365,7 +376,8 @@ implements InvitationListener {
 				remoteCompared = true;
 				remoteMatched = false;
 				if (localMatched)
-					setView(new CodesDoNotMatchView(AddContactActivity.this));
+					setView(new ErrorView(AddContactActivity.this, R.string.codes_do_not_match,
+							R.string.interfering));
 			}
 		});
 	}
@@ -382,7 +394,8 @@ implements InvitationListener {
 	public void pseudonymExchangeFailed() {
 		runOnUiThread(new Runnable() {
 			public void run() {
-				setView(new ConnectionFailedView(AddContactActivity.this));
+				setView(new ErrorView(AddContactActivity.this, R.string.connection_failed,
+						R.string.could_not_find_contact));
 			}
 		});
 	}
diff --git a/briar-android/src/org/briarproject/android/invitation/AddContactView.java b/briar-android/src/org/briarproject/android/invitation/AddContactView.java
index 2a6b978493557988f47b2663a44a9c018dfda631..6a6b300be31f4e03f0ebc459df86f5d073bede7a 100644
--- a/briar-android/src/org/briarproject/android/invitation/AddContactView.java
+++ b/briar-android/src/org/briarproject/android/invitation/AddContactView.java
@@ -1,31 +1,22 @@
 package org.briarproject.android.invitation;
 
-import static android.view.Gravity.CENTER_HORIZONTAL;
-import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH;
-
-import org.briarproject.android.util.LayoutUtils;
-
 import android.content.Context;
 import android.widget.LinearLayout;
 
 abstract class AddContactView extends LinearLayout {
 
-	protected final int pad;
-
+	static final public int CODE_LEN = 6;
 	protected AddContactActivity container = null;
 
 	AddContactView(Context ctx) {
 		super(ctx);
-		pad = LayoutUtils.getPadding(ctx);
 	}
 
 	void init(AddContactActivity container) {
 		this.container = container;
-		setLayoutParams(MATCH_MATCH);
-		setOrientation(VERTICAL);
-		setGravity(CENTER_HORIZONTAL);
 		populate();
 	}
 
 	abstract void populate();
+
 }
diff --git a/briar-android/src/org/briarproject/android/invitation/ChooseIdentityView.java b/briar-android/src/org/briarproject/android/invitation/ChooseIdentityView.java
index 5ecd1898fadb719cd74b7ff691af18c64d8da260..f609eb93f2d00b015e1fa4ac8a7ec856f814efe4 100644
--- a/briar-android/src/org/briarproject/android/invitation/ChooseIdentityView.java
+++ b/briar-android/src/org/briarproject/android/invitation/ChooseIdentityView.java
@@ -21,6 +21,7 @@ import org.briarproject.api.LocalAuthor;
 
 import android.content.Context;
 import android.content.Intent;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.AdapterView;
@@ -35,7 +36,6 @@ implements OnItemSelectedListener, OnClickListener {
 
 	private LocalAuthorSpinnerAdapter adapter = null;
 	private Spinner spinner = null;
-	private Button continueButton = null;
 
 	ChooseIdentityView(Context ctx) {
 		super(ctx);
@@ -45,34 +45,22 @@ implements OnItemSelectedListener, OnClickListener {
 		removeAllViews();
 		Context ctx = getContext();
 
-		LinearLayout innerLayout = new LinearLayout(ctx);
-		innerLayout.setLayoutParams(MATCH_WRAP);
-		innerLayout.setOrientation(HORIZONTAL);
-		innerLayout.setGravity(CENTER);
+		LayoutInflater inflater = (LayoutInflater) ctx.getSystemService
+				(Context.LAYOUT_INFLATER_SERVICE);
+		View view = inflater.inflate(R.layout.invitation_bluetooth_start, this);
 
-		TextView yourNickname = new TextView(ctx);
-		yourNickname.setTextSize(18);
-		yourNickname.setPadding(pad, pad, pad, pad);
-		yourNickname.setText(R.string.your_nickname);
-		innerLayout.addView(yourNickname);
+		// current step
+		// TODO this could go into the ActionBar eventually
+		TextView step = (TextView) view.findViewById(R.id.stepView);
+		step.setText(String.format(ctx.getString(R.string.step), 1, 3));
 
 		adapter = new LocalAuthorSpinnerAdapter(ctx, false);
-		spinner = new Spinner(ctx);
+		spinner = (Spinner) view.findViewById(R.id.spinner);
 		spinner.setAdapter(adapter);
 		spinner.setOnItemSelectedListener(this);
-		innerLayout.addView(spinner);
-		addView(innerLayout);
 
-		TextView faceToFace = new TextView(ctx);
-		faceToFace.setPadding(pad, pad, pad, pad);
-		faceToFace.setText(R.string.face_to_face);
-		addView(faceToFace);
-
-		continueButton = new Button(ctx);
-		continueButton.setLayoutParams(WRAP_WRAP);
-		continueButton.setText(R.string.continue_button);
+		Button continueButton = (Button) view.findViewById(R.id.continueButton);
 		continueButton.setOnClickListener(this);
-		addView(continueButton);
 
 		container.loadLocalAuthors();
 	}
diff --git a/briar-android/src/org/briarproject/android/invitation/CodeEntryListener.java b/briar-android/src/org/briarproject/android/invitation/CodeEntryListener.java
deleted file mode 100644
index e63c8b177797eedd09d2e081fb6b7df42519bce9..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/invitation/CodeEntryListener.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.briarproject.android.invitation;
-
-interface CodeEntryListener {
-
-	void codeEntered(int remoteCode);
-}
diff --git a/briar-android/src/org/briarproject/android/invitation/CodeEntryView.java b/briar-android/src/org/briarproject/android/invitation/CodeEntryView.java
deleted file mode 100644
index d15bfdab37232a801d991765d1de003421170cc4..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/invitation/CodeEntryView.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package org.briarproject.android.invitation;
-
-import static android.content.Context.INPUT_METHOD_SERVICE;
-import static android.text.InputType.TYPE_CLASS_NUMBER;
-import static android.view.Gravity.CENTER;
-import static android.view.Gravity.CENTER_HORIZONTAL;
-import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
-import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP;
-
-import org.briarproject.R;
-import org.briarproject.android.util.LayoutUtils;
-
-import android.content.Context;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
-
-class CodeEntryView extends LinearLayout
-implements OnEditorActionListener, OnClickListener {
-
-	private final int pad;
-
-	private CodeEntryListener listener = null;
-	private EditText codeEntry = null;
-	private Button continueButton = null;
-
-	public CodeEntryView(Context ctx) {
-		super(ctx);
-		pad = LayoutUtils.getPadding(ctx);
-	}
-
-	void init(CodeEntryListener listener, String prompt) {
-		this.listener = listener;
-		setOrientation(VERTICAL);
-		setGravity(CENTER_HORIZONTAL);
-
-		Context ctx = getContext();
-		TextView enterCode = new TextView(ctx);
-		enterCode.setGravity(CENTER_HORIZONTAL);
-		enterCode.setPadding(pad, pad, pad, 0);
-		enterCode.setText(prompt);
-		addView(enterCode);
-
-		LinearLayout innerLayout = new LinearLayout(ctx);
-		innerLayout.setOrientation(HORIZONTAL);
-		innerLayout.setGravity(CENTER);
-
-		codeEntry = new EditText(ctx) {
-			@Override
-			protected void onTextChanged(CharSequence text, int start,
-					int lengthBefore, int lengthAfter) {
-				if (continueButton != null)
-					continueButton.setEnabled(getText().length() == 6);
-			}
-		};
-		codeEntry.setId(1); // FIXME: State is not saved and restored
-		codeEntry.setTextSize(26);
-		codeEntry.setOnEditorActionListener(this);
-		codeEntry.setMinEms(5);
-		codeEntry.setMaxEms(5);
-		codeEntry.setMaxLines(1);
-		codeEntry.setInputType(TYPE_CLASS_NUMBER);
-		innerLayout.addView(codeEntry);
-
-		continueButton = new Button(ctx);
-		continueButton.setLayoutParams(WRAP_WRAP);
-		continueButton.setText(R.string.continue_button);
-		continueButton.setEnabled(false);
-		continueButton.setOnClickListener(this);
-		innerLayout.addView(continueButton);
-		addView(innerLayout);
-	}
-
-	public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
-		if (!validateAndReturnCode()) codeEntry.setText("");
-		return true;
-	}
-
-	public void onClick(View view) {
-		if (!validateAndReturnCode()) codeEntry.setText("");
-	}
-
-	private boolean validateAndReturnCode() {
-		String remoteCodeString = codeEntry.getText().toString();
-		int remoteCode;
-		try {
-			remoteCode = Integer.parseInt(remoteCodeString);
-		} catch (NumberFormatException e) {
-			return false;
-		}
-		// Hide the soft keyboard
-		Object o = getContext().getSystemService(INPUT_METHOD_SERVICE);
-		((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
-		listener.codeEntered(remoteCode);
-		return true;
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/invitation/ConfirmationCodeView.java b/briar-android/src/org/briarproject/android/invitation/ConfirmationCodeView.java
index 7c52cd880b0e1395a8e025e4953699d2f995e742..118744cc928162f3a7db100299932eba5b838065 100644
--- a/briar-android/src/org/briarproject/android/invitation/ConfirmationCodeView.java
+++ b/briar-android/src/org/briarproject/android/invitation/ConfirmationCodeView.java
@@ -1,60 +1,126 @@
 package org.briarproject.android.invitation;
 
-import static android.view.Gravity.CENTER;
-import static android.view.Gravity.CENTER_HORIZONTAL;
+import android.content.Context;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
 
 import org.briarproject.R;
 
-import android.content.Context;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
+import static android.content.Context.INPUT_METHOD_SERVICE;
+import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
+
+class ConfirmationCodeView extends AddContactView {
 
-class ConfirmationCodeView extends AddContactView implements CodeEntryListener {
+	public enum ConfirmationState { CONNECTED, ENTER_CODE, WAIT_FOR_CONTACT, DETAILS }
+	private ConfirmationState state;
 
 	ConfirmationCodeView(Context ctx) {
 		super(ctx);
+		this.state = ConfirmationState.ENTER_CODE;
+	}
+
+	ConfirmationCodeView(Context ctx, ConfirmationState state) {
+		super(ctx);
+		this.state = state;
 	}
 
 	void populate() {
 		removeAllViews();
 		Context ctx = getContext();
-		LinearLayout innerLayout = new LinearLayout(ctx);
-		innerLayout.setOrientation(HORIZONTAL);
-		innerLayout.setGravity(CENTER);
-
-		ImageView icon = new ImageView(ctx);
-		icon.setImageResource(R.drawable.navigation_accept);
-		innerLayout.addView(icon);
-
-		TextView connected = new TextView(ctx);
-		connected.setTextSize(22);
-		connected.setPadding(pad, pad, pad, pad);
-		connected.setText(R.string.connected_to_contact);
-		innerLayout.addView(connected);
-		addView(innerLayout);
-
-		TextView yourCode = new TextView(ctx);
-		yourCode.setGravity(CENTER_HORIZONTAL);
-		yourCode.setPadding(pad, pad, pad, pad);
-		yourCode.setText(R.string.your_confirmation_code);
-		addView(yourCode);
-
-		TextView code = new TextView(ctx);
-		code.setGravity(CENTER_HORIZONTAL);
-		code.setTextSize(50);
-		code.setPadding(pad, 0, pad, pad);
+
+		LayoutInflater inflater = (LayoutInflater) ctx.getSystemService
+				(Context.LAYOUT_INFLATER_SERVICE);
+		View view = inflater.inflate(R.layout.invitation_bluetooth_confirmation_code, this);
+
+		// current step
+		// TODO this could go into the ActionBar eventually
+		TextView step = (TextView) view.findViewById(R.id.stepView);
+		step.setText(String.format(ctx.getString(R.string.step), 3, 3));
+
+		// local confirmation code
+		TextView code = (TextView) view.findViewById(R.id.codeView);
 		int localCode = container.getLocalConfirmationCode();
 		code.setText(String.format("%06d", localCode));
-		addView(code);
 
-		CodeEntryView codeEntry = new CodeEntryView(ctx);
-		String enter = container.getString(R.string.enter_confirmation_code);
-		codeEntry.init(this, enter);
-		addView(codeEntry);
+		if (state != ConfirmationState.ENTER_CODE) {
+			// hide views we no longer need
+			view.findViewById(R.id.enterCodeTextView).setVisibility(View.GONE);
+			view.findViewById(R.id.codeEntryView).setVisibility(View.GONE);
+			view.findViewById(R.id.continueButton).setVisibility(View.GONE);
+
+			// show progress indicator
+			view.findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
+
+			// show what we are waiting for
+			TextView connecting = (TextView) view.findViewById(R.id.waitingView);
+			int textId;
+			if (state == ConfirmationState.CONNECTED) {
+				textId = R.string.calculating_confirmation_code;
+				view.findViewById(R.id.yourConfirmationCodeView).setVisibility(View.GONE);
+				view.findViewById(R.id.codeView).setVisibility(View.GONE);
+			} else if (state == ConfirmationState.WAIT_FOR_CONTACT) {
+				textId = R.string.waiting_for_contact;
+			} else {
+				textId = R.string.exchanging_contact_details;
+			}
+			connecting.setText(ctx.getString(textId));
+			connecting.setVisibility(View.VISIBLE);
+		}
+		else {
+			// handle click on continue button
+			final EditText codeEntry = (EditText) view.findViewById(R.id.codeEntryView);
+			final Button continueButton = (Button) view.findViewById(R.id.continueButton);
+			continueButton.setOnClickListener(new OnClickListener() {
+				@Override
+				public void onClick(View v) {
+					send(codeEntry);
+				}
+			});
+
+			// activate continue button only when we have a 6 digit (CODE_LEN) code
+			codeEntry.addTextChangedListener(new TextWatcher() {
+				@Override
+				public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+				}
+
+				@Override
+				public void onTextChanged(CharSequence s, int start, int before, int count) {
+					continueButton.setEnabled(codeEntry.getText().length() == CODE_LEN);
+				}
+
+				@Override
+				public void afterTextChanged(Editable s) {
+				}
+			});
+
+			codeEntry.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+				@Override
+				public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+					if (actionId == EditorInfo.IME_ACTION_GO && v.getText().length() == CODE_LEN) {
+						send(v);
+						return true;
+					}
+					return false;
+				}
+			});
+		}
 	}
 
-	public void codeEntered(int remoteCode) {
-		container.remoteConfirmationCodeEntered(remoteCode);
+	private void send(TextView codeEntry) {
+		int code = Integer.parseInt(codeEntry.getText().toString());
+		container.remoteConfirmationCodeEntered(code);
+
+		// Hide the soft keyboard
+		Object o = getContext().getSystemService(INPUT_METHOD_SERVICE);
+		((InputMethodManager) o).hideSoftInputFromWindow(codeEntry.getWindowToken(), 0);
 	}
+
 }
diff --git a/briar-android/src/org/briarproject/android/invitation/ConnectedView.java b/briar-android/src/org/briarproject/android/invitation/ConnectedView.java
deleted file mode 100644
index b9a51abec686244cf8044856933bcc958b16cfdb..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/invitation/ConnectedView.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.briarproject.android.invitation;
-
-import static android.view.Gravity.CENTER;
-
-import org.briarproject.R;
-
-import android.content.Context;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-class ConnectedView extends AddContactView {
-
-	ConnectedView(Context ctx) {
-		super(ctx);
-	}
-
-	void populate() {
-		removeAllViews();
-		Context ctx = getContext();
-		LinearLayout innerLayout = new LinearLayout(ctx);
-		innerLayout.setOrientation(HORIZONTAL);
-		innerLayout.setGravity(CENTER);
-
-		ImageView icon = new ImageView(ctx);
-		icon.setImageResource(R.drawable.navigation_accept);
-		innerLayout.addView(icon);
-
-		TextView connected = new TextView(ctx);
-		connected.setTextSize(22);
-		connected.setPadding(pad, pad, pad, pad);
-		connected.setText(R.string.connected_to_contact);
-		innerLayout.addView(connected);
-		addView(innerLayout);
-
-		innerLayout = new LinearLayout(ctx);
-		innerLayout.setOrientation(HORIZONTAL);
-		innerLayout.setGravity(CENTER);
-
-		ProgressBar progress = new ProgressBar(ctx);
-		progress.setIndeterminate(true);
-		progress.setPadding(pad, pad, pad, pad);
-		innerLayout.addView(progress);
-
-		TextView connecting = new TextView(ctx);
-		connecting.setText(R.string.calculating_confirmation_code);
-		innerLayout.addView(connecting);
-		addView(innerLayout);
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/invitation/ConnectionFailedView.java b/briar-android/src/org/briarproject/android/invitation/ConnectionFailedView.java
deleted file mode 100644
index 346d9788c41d9b1c89623727b35c92831873384f..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/invitation/ConnectionFailedView.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.briarproject.android.invitation;
-
-import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE;
-import static android.bluetooth.BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION;
-import static android.view.Gravity.CENTER;
-import static org.briarproject.android.invitation.AddContactActivity.REQUEST_BLUETOOTH;
-import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP;
-
-import org.briarproject.R;
-
-import android.content.Context;
-import android.content.Intent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-class ConnectionFailedView extends AddContactView implements OnClickListener {
-
-	private Button tryAgainButton = null;
-
-	ConnectionFailedView(Context ctx) {
-		super(ctx);
-	}
-
-	void populate() {
-		removeAllViews();
-		Context ctx = getContext();
-		LinearLayout innerLayout = new LinearLayout(ctx);
-		innerLayout.setOrientation(HORIZONTAL);
-		innerLayout.setGravity(CENTER);
-
-		ImageView icon = new ImageView(ctx);
-		icon.setImageResource(R.drawable.alerts_and_states_error);
-		innerLayout.addView(icon);
-
-		TextView failed = new TextView(ctx);
-		failed.setTextSize(22);
-		failed.setPadding(pad, pad, pad, pad);
-		failed.setText(R.string.connection_failed);
-		innerLayout.addView(failed);
-		addView(innerLayout);
-
-		TextView couldNotFind = new TextView(ctx);
-		couldNotFind.setGravity(CENTER);
-		couldNotFind.setPadding(pad, 0, pad, pad);
-		couldNotFind.setText(R.string.could_not_find_contact);
-		addView(couldNotFind);
-
-		tryAgainButton = new Button(ctx);
-		tryAgainButton.setLayoutParams(WRAP_WRAP);
-		tryAgainButton.setText(R.string.try_again_button);
-		tryAgainButton.setOnClickListener(this);
-		addView(tryAgainButton);
-	}
-
-	public void onClick(View view) {
-		Intent i = new Intent(ACTION_REQUEST_DISCOVERABLE);
-		i.putExtra(EXTRA_DISCOVERABLE_DURATION, 120);
-		container.startActivityForResult(i, REQUEST_BLUETOOTH);
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/invitation/ConnectionView.java b/briar-android/src/org/briarproject/android/invitation/ConnectionView.java
deleted file mode 100644
index e85b100c0cf0a26c3d843bf09603f01afd7deebc..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/invitation/ConnectionView.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.briarproject.android.invitation;
-
-import static android.view.Gravity.CENTER;
-import static android.view.Gravity.CENTER_HORIZONTAL;
-
-import org.briarproject.R;
-
-import android.content.Context;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-class ConnectionView extends AddContactView {
-
-	ConnectionView(Context ctx) {
-		super(ctx);
-	}
-
-	void populate() {
-		removeAllViews();
-		Context ctx = getContext();
-		TextView yourCode = new TextView(ctx);
-		yourCode.setGravity(CENTER_HORIZONTAL);
-		yourCode.setPadding(pad, pad, pad, pad);
-		yourCode.setText(R.string.your_invitation_code);
-		addView(yourCode);
-
-		TextView code = new TextView(ctx);
-		code.setGravity(CENTER_HORIZONTAL);
-		code.setTextSize(50);
-		code.setPadding(pad, 0, pad, pad);
-		int localCode = container.getLocalInvitationCode();
-		code.setText(String.format("%06d", localCode));
-		addView(code);
-
-		LinearLayout innerLayout = new LinearLayout(ctx);
-		innerLayout.setOrientation(HORIZONTAL);
-		innerLayout.setGravity(CENTER);
-
-		ProgressBar progress = new ProgressBar(ctx);
-		progress.setPadding(pad, pad, pad, pad);
-		progress.setIndeterminate(true);
-		innerLayout.addView(progress);
-
-		TextView connecting = new TextView(ctx);
-		int remoteCode = container.getRemoteInvitationCode();
-		String format = container.getString(R.string.searching_format);
-		connecting.setText(String.format(format, remoteCode));
-		innerLayout.addView(connecting);
-
-		addView(innerLayout);
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/invitation/ContactDetailsView.java b/briar-android/src/org/briarproject/android/invitation/ContactDetailsView.java
deleted file mode 100644
index 9e8a83f78c4b838a69052efdc13569134bed527a..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/invitation/ContactDetailsView.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.briarproject.android.invitation;
-
-import static android.view.Gravity.CENTER;
-import static android.view.Gravity.CENTER_HORIZONTAL;
-
-import org.briarproject.R;
-
-import android.content.Context;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-class ContactDetailsView extends AddContactView {
-
-	ContactDetailsView(Context ctx) {
-		super(ctx);
-	}
-
-	void populate() {
-		removeAllViews();
-		Context ctx = getContext();
-		LinearLayout innerLayout = new LinearLayout(ctx);
-		innerLayout.setOrientation(HORIZONTAL);
-		innerLayout.setGravity(CENTER);
-
-		ImageView icon = new ImageView(ctx);
-		icon.setImageResource(R.drawable.navigation_accept);
-		innerLayout.addView(icon);
-
-		TextView connected = new TextView(ctx);
-		connected.setTextSize(22);
-		connected.setPadding(pad, pad, pad, pad);
-		connected.setText(R.string.connected_to_contact);
-		innerLayout.addView(connected);
-		addView(innerLayout);
-
-		TextView yourCode = new TextView(ctx);
-		yourCode.setGravity(CENTER_HORIZONTAL);
-		yourCode.setPadding(pad, 0, pad, pad);
-		yourCode.setText(R.string.your_confirmation_code);
-		addView(yourCode);
-
-		TextView code = new TextView(ctx);
-		code.setGravity(CENTER_HORIZONTAL);
-		code.setTextSize(50);
-		code.setPadding(pad, 0, pad, pad);
-		int localCode = container.getLocalConfirmationCode();
-		code.setText(String.format("%06d", localCode));
-		addView(code);
-
-		innerLayout = new LinearLayout(ctx);
-		innerLayout.setOrientation(HORIZONTAL);
-		innerLayout.setGravity(CENTER);
-
-		ProgressBar progress = new ProgressBar(ctx);
-		progress.setIndeterminate(true);
-		progress.setPadding(pad, pad, pad, pad);
-		innerLayout.addView(progress);
-
-		TextView connecting = new TextView(ctx);
-		connecting.setText(R.string.exchanging_contact_details);
-		innerLayout.addView(connecting);
-		addView(innerLayout);
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/invitation/CodesDoNotMatchView.java b/briar-android/src/org/briarproject/android/invitation/ErrorView.java
similarity index 52%
rename from briar-android/src/org/briarproject/android/invitation/CodesDoNotMatchView.java
rename to briar-android/src/org/briarproject/android/invitation/ErrorView.java
index ea800ccfc8cd4c2028bf074fd82da482062938c5..0f17a4ebf02fbf7020577daa1a7c5e1094b60a5c 100644
--- a/briar-android/src/org/briarproject/android/invitation/CodesDoNotMatchView.java
+++ b/briar-android/src/org/briarproject/android/invitation/ErrorView.java
@@ -10,6 +10,7 @@ import org.briarproject.R;
 
 import android.content.Context;
 import android.content.Intent;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
@@ -17,41 +18,39 @@ import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-class CodesDoNotMatchView extends AddContactView implements OnClickListener {
+class ErrorView extends AddContactView implements OnClickListener {
 
-	CodesDoNotMatchView(Context ctx) {
+	private final int error;
+	private final int explanation;
+
+	ErrorView(Context ctx) {
+		super(ctx);
+		this.error = R.string.connection_failed;
+		this.explanation = R.string.could_not_find_contact;
+	}
+
+	ErrorView(Context ctx, int error, int explanation) {
 		super(ctx);
+		this.error = error;
+		this.explanation = explanation;
 	}
 
 	void populate() {
 		removeAllViews();
 		Context ctx = getContext();
-		LinearLayout innerLayout = new LinearLayout(ctx);
-		innerLayout.setOrientation(HORIZONTAL);
-		innerLayout.setGravity(CENTER);
-
-		ImageView icon = new ImageView(ctx);
-		icon.setImageResource(R.drawable.alerts_and_states_error);
-		innerLayout.addView(icon);
-
-		TextView failed = new TextView(ctx);
-		failed.setTextSize(22);
-		failed.setPadding(pad, pad, pad, pad);
-		failed.setText(R.string.codes_do_not_match);
-		innerLayout.addView(failed);
-		addView(innerLayout);
-
-		TextView interfering = new TextView(ctx);
-		interfering.setGravity(CENTER);
-		interfering.setPadding(pad, 0, pad, pad);
-		interfering.setText(R.string.interfering);
-		addView(interfering);
-
-		Button tryAgainButton = new Button(ctx);
-		tryAgainButton.setLayoutParams(WRAP_WRAP);
-		tryAgainButton.setText(R.string.try_again_button);
+
+		LayoutInflater inflater = (LayoutInflater) ctx.getSystemService
+				(Context.LAYOUT_INFLATER_SERVICE);
+		View view = inflater.inflate(R.layout.invitation_error, this);
+
+		TextView errorView = (TextView) view.findViewById(R.id.errorTextView);
+		errorView.setText(ctx.getString(error));
+
+		TextView explanationView = (TextView) view.findViewById(R.id.explanationTextView);
+		explanationView.setText(ctx.getString(explanation));
+
+		Button tryAgainButton = (Button) view.findViewById(R.id.tryAgainButton);
 		tryAgainButton.setOnClickListener(this);
-		addView(tryAgainButton);
 	}
 
 	public void onClick(View view) {
diff --git a/briar-android/src/org/briarproject/android/invitation/InvitationCodeView.java b/briar-android/src/org/briarproject/android/invitation/InvitationCodeView.java
index 1f014fc0c9c09536ef78433c96927155011cf72c..ebd6fcc13eaf79c53a2dd9b64193999877c2b63f 100644
--- a/briar-android/src/org/briarproject/android/invitation/InvitationCodeView.java
+++ b/briar-android/src/org/briarproject/android/invitation/InvitationCodeView.java
@@ -1,42 +1,116 @@
 package org.briarproject.android.invitation;
 
-import static android.view.Gravity.CENTER_HORIZONTAL;
+import android.content.Context;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
 
 import org.briarproject.R;
 
-import android.content.Context;
-import android.widget.TextView;
+import static android.content.Context.INPUT_METHOD_SERVICE;
+import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
 
-class InvitationCodeView extends AddContactView implements CodeEntryListener {
+class InvitationCodeView extends AddContactView {
 
-	InvitationCodeView(Context ctx) {
+	private boolean waiting;
+
+	InvitationCodeView(Context ctx, boolean waiting) {
 		super(ctx);
+		this.waiting = waiting;
+	}
+
+	InvitationCodeView(Context ctx) {
+		this(ctx, false);
 	}
 
 	void populate() {
 		removeAllViews();
 		Context ctx = getContext();
-		TextView yourCode = new TextView(ctx);
-		yourCode.setGravity(CENTER_HORIZONTAL);
-		yourCode.setPadding(pad, pad, pad, pad);
-		yourCode.setText(R.string.your_invitation_code);
-		addView(yourCode);
-
-		TextView code = new TextView(ctx);
-		code.setGravity(CENTER_HORIZONTAL);
-		code.setTextSize(50);
-		code.setPadding(pad, 0, pad, pad);
+
+		LayoutInflater inflater = (LayoutInflater) ctx.getSystemService
+				(Context.LAYOUT_INFLATER_SERVICE);
+		View view = inflater.inflate(R.layout.invitation_bluetooth_invitation_code, this);
+
+		// current step
+		// TODO this could go into the ActionBar eventually
+		TextView step = (TextView) view.findViewById(R.id.stepView);
+		step.setText(String.format(ctx.getString(R.string.step), 2, 3));
+
+		// local invitation code
+		TextView code = (TextView) view.findViewById(R.id.codeView);
 		int localCode = container.getLocalInvitationCode();
 		code.setText(String.format("%06d", localCode));
-		addView(code);
 
-		CodeEntryView codeEntry = new CodeEntryView(ctx);
-		String enter = container.getString(R.string.enter_invitation_code);
-		codeEntry.init(this, enter);
-		addView(codeEntry);
+		if (waiting) {
+			// hide views we no longer need
+			view.findViewById(R.id.enterCodeTextView).setVisibility(View.GONE);
+			view.findViewById(R.id.codeEntryView).setVisibility(View.GONE);
+			view.findViewById(R.id.continueButton).setVisibility(View.GONE);
+
+			// show progress indicator
+			view.findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
+
+			// show which code we are waiting for
+			TextView connecting = (TextView) view.findViewById(R.id.waitingView);
+			int remoteCode = container.getRemoteInvitationCode();
+			String format = container.getString(R.string.searching_format);
+			connecting.setText(String.format(format, remoteCode));
+			connecting.setVisibility(View.VISIBLE);
+		}
+		else {
+			// handle click on continue button
+			final EditText codeEntry = (EditText) view.findViewById(R.id.codeEntryView);
+			final Button continueButton = (Button) view.findViewById(R.id.continueButton);
+			continueButton.setOnClickListener(new OnClickListener() {
+				@Override
+				public void onClick(View v) {
+					send(codeEntry);
+				}
+			});
+
+			// activate continue button only when we have a 6 digit (CODE_LEN) code
+			codeEntry.addTextChangedListener(new TextWatcher() {
+				@Override
+				public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+				}
+
+				@Override
+				public void onTextChanged(CharSequence s, int start, int before, int count) {
+					continueButton.setEnabled(codeEntry.getText().length() == CODE_LEN);
+				}
+
+				@Override
+				public void afterTextChanged(Editable s) {
+				}
+			});
+
+			codeEntry.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+				@Override
+				public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+					if (actionId == EditorInfo.IME_ACTION_GO && v.getText().length() == CODE_LEN) {
+						send(v);
+						return true;
+					}
+					return false;
+				}
+			});
+		}
 	}
 
-	public void codeEntered(int remoteCode) {
-		container.remoteInvitationCodeEntered(remoteCode);
+	private void send(TextView codeEntry) {
+		int code = Integer.parseInt(codeEntry.getText().toString());
+		container.remoteInvitationCodeEntered(code);
+
+		// Hide the soft keyboard
+		Object o = getContext().getSystemService(INPUT_METHOD_SERVICE);
+		((InputMethodManager) o).hideSoftInputFromWindow(codeEntry.getWindowToken(), 0);
 	}
+
 }
diff --git a/briar-android/src/org/briarproject/android/invitation/WaitForContactView.java b/briar-android/src/org/briarproject/android/invitation/WaitForContactView.java
deleted file mode 100644
index f417dd113940a72861d448a07fde7ddc12c9bbc3..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/invitation/WaitForContactView.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.briarproject.android.invitation;
-
-import static android.view.Gravity.CENTER;
-import static android.view.Gravity.CENTER_HORIZONTAL;
-
-import org.briarproject.R;
-
-import android.content.Context;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-class WaitForContactView extends AddContactView {
-
-	WaitForContactView(Context ctx) {
-		super(ctx);
-	}
-
-	void populate() {
-		removeAllViews();
-		Context ctx = getContext();
-		LinearLayout innerLayout = new LinearLayout(ctx);
-		innerLayout.setOrientation(HORIZONTAL);
-		innerLayout.setGravity(CENTER);
-
-		ImageView icon = new ImageView(ctx);
-		icon.setImageResource(R.drawable.navigation_accept);
-		innerLayout.addView(icon);
-
-		TextView connected = new TextView(ctx);
-		connected.setTextSize(22);
-		connected.setPadding(pad, pad, pad, pad);
-		connected.setText(R.string.connected_to_contact);
-		innerLayout.addView(connected);
-		addView(innerLayout);
-
-		TextView yourCode = new TextView(ctx);
-		yourCode.setGravity(CENTER_HORIZONTAL);
-		yourCode.setPadding(pad, 0, pad, pad);
-		yourCode.setText(R.string.your_confirmation_code);
-		addView(yourCode);
-
-		TextView code = new TextView(ctx);
-		code.setGravity(CENTER_HORIZONTAL);
-		code.setTextSize(50);
-		code.setPadding(pad, 0, pad, pad);
-		int localCode = container.getLocalConfirmationCode();
-		code.setText(String.format("%06d", localCode));
-		addView(code);
-
-		innerLayout = new LinearLayout(ctx);
-		innerLayout.setOrientation(HORIZONTAL);
-		innerLayout.setGravity(CENTER);
-
-		ProgressBar progress = new ProgressBar(ctx);
-		progress.setIndeterminate(true);
-		progress.setPadding(pad, pad, pad, pad);
-		innerLayout.addView(progress);
-
-		TextView connecting = new TextView(ctx);
-		connecting.setText(R.string.waiting_for_contact);
-		innerLayout.addView(connecting);
-		addView(innerLayout);
-	}
-}