Merge branch '87-improve-adding-contacts' into 'master'

Improve Adding Contacts

These changes provide more detailed instructions for adding contacts.

Users were confused by the process of adding a contact for the first time.
This change adds additional explanation and a picture of what is going on.

Closes #87

This change also shows the current step and the total number of steps when adding a contact.

Closes #33

The UI was transferred into XML files and lots of redundant code was deleted such as the custom CodeEntryView.

Please note that I did not implement a countdown for Bluetooth discoverability (#71), because of the way how the state machine resets the entire content view of the activity. This should probably be refactored to use fragments which would make the code cleaner and a permanent progress bar easier to implement.

See merge request !15
This commit is contained in:
akwizgran
2015-12-14 17:55:36 +00:00
21 changed files with 737 additions and 557 deletions

View File

@@ -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>

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"/>

View File

@@ -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>
</resources>

View File

@@ -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));
}
});
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -1,6 +0,0 @@
package org.briarproject.android.invitation;
interface CodeEntryListener {
void codeEntered(int remoteCode);
}

View File

@@ -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;
}
}

View File

@@ -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 implements CodeEntryListener {
class ConfirmationCodeView extends AddContactView {
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);
LayoutInflater inflater = (LayoutInflater) ctx.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.invitation_bluetooth_confirmation_code, this);
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);
// 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));
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);
// 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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
LayoutInflater inflater = (LayoutInflater) ctx.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.invitation_error, this);
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 errorView = (TextView) view.findViewById(R.id.errorTextView);
errorView.setText(ctx.getString(error));
TextView interfering = new TextView(ctx);
interfering.setGravity(CENTER);
interfering.setPadding(pad, 0, pad, pad);
interfering.setText(R.string.interfering);
addView(interfering);
TextView explanationView = (TextView) view.findViewById(R.id.explanationTextView);
explanationView.setText(ctx.getString(explanation));
Button tryAgainButton = new Button(ctx);
tryAgainButton.setLayoutParams(WRAP_WRAP);
tryAgainButton.setText(R.string.try_again_button);
Button tryAgainButton = (Button) view.findViewById(R.id.tryAgainButton);
tryAgainButton.setOnClickListener(this);
addView(tryAgainButton);
}
public void onClick(View view) {

View File

@@ -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 {
private boolean waiting;
InvitationCodeView(Context ctx, boolean waiting) {
super(ctx);
this.waiting = waiting;
}
InvitationCodeView(Context ctx) {
super(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);
}
}

View File

@@ -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);
}
}