From 2046ed0cac7e5ebc973867bd6fcf2be6ab085d9f Mon Sep 17 00:00:00 2001 From: akwizgran <michael@briarproject.org> Date: Tue, 6 Nov 2012 15:04:01 +0000 Subject: [PATCH] Merged Android invitation UI from add_contact repo. --- AndroidManifest.xml | 51 +++++++-- res/drawable-hdpi/ic_launcher.png | Bin 0 -> 2364 bytes res/drawable-ldpi/ic_launcher.png | Bin 0 -> 1276 bytes res/drawable-ldpi/iconic_check_alt_green.png | Bin 0 -> 499 bytes res/drawable-ldpi/iconic_x_alt_red.png | Bin 0 -> 552 bytes res/drawable-mdpi/ic_launcher.png | Bin 0 -> 1591 bytes res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 3192 bytes res/layout/activity_add_contact.xml | 5 + res/layout/activity_codes_do_not_match.xml | 5 + res/layout/activity_connection.xml | 5 + res/layout/activity_connection_failed.xml | 5 + res/layout/activity_connection_succeeded.xml | 5 + res/layout/activity_contact_added.xml | 5 + res/layout/activity_invitation_code.xml | 5 + res/layout/activity_network_setup.xml | 5 + res/layout/activity_test_bluetooth.xml | 71 +++++++++++++ res/layout/activity_wait_for_contact.xml | 5 + res/values/strings.xml | 36 +++++++ src/net/sf/briar/HelloWorldActivity.java | 30 +++++- .../invitation/BluetoothStateListener.java | 6 ++ .../android/invitation/BluetoothWidget.java | 71 +++++++++++++ .../android/invitation/CodeEntryListener.java | 6 ++ .../android/invitation/CodeEntryWidget.java | 76 ++++++++++++++ .../invitation/CodesDoNotMatchActivity.java | 54 ++++++++++ .../invitation/ConfirmationCodeActivity.java | 69 ++++++++++++ .../invitation/ConfirmationListener.java | 8 ++ .../invitation/ConnectionActivity.java | 99 ++++++++++++++++++ .../invitation/ConnectionFailedActivity.java | 96 +++++++++++++++++ .../invitation/ConnectionListener.java | 8 ++ .../invitation/ContactAddedActivity.java | 91 ++++++++++++++++ .../invitation/InvitationCodeActivity.java | 48 +++++++++ .../android/invitation/InvitationManager.java | 26 +++++ .../invitation/InvitationManagerFactory.java | 14 +++ .../invitation/InvitationManagerImpl.java | 67 ++++++++++++ .../invitation/NetworkSetupActivity.java | 88 ++++++++++++++++ .../invitation/WaitForContactActivity.java | 76 ++++++++++++++ .../android/invitation/WifiStateListener.java | 6 ++ .../briar/android/invitation/WifiWidget.java | 77 ++++++++++++++ 38 files changed, 1209 insertions(+), 10 deletions(-) create mode 100644 res/drawable-hdpi/ic_launcher.png create mode 100644 res/drawable-ldpi/ic_launcher.png create mode 100644 res/drawable-ldpi/iconic_check_alt_green.png create mode 100644 res/drawable-ldpi/iconic_x_alt_red.png create mode 100644 res/drawable-mdpi/ic_launcher.png create mode 100644 res/drawable-xhdpi/ic_launcher.png create mode 100644 res/layout/activity_add_contact.xml create mode 100644 res/layout/activity_codes_do_not_match.xml create mode 100644 res/layout/activity_connection.xml create mode 100644 res/layout/activity_connection_failed.xml create mode 100644 res/layout/activity_connection_succeeded.xml create mode 100644 res/layout/activity_contact_added.xml create mode 100644 res/layout/activity_invitation_code.xml create mode 100644 res/layout/activity_network_setup.xml create mode 100644 res/layout/activity_test_bluetooth.xml create mode 100644 res/layout/activity_wait_for_contact.xml create mode 100644 src/net/sf/briar/android/invitation/BluetoothStateListener.java create mode 100644 src/net/sf/briar/android/invitation/BluetoothWidget.java create mode 100644 src/net/sf/briar/android/invitation/CodeEntryListener.java create mode 100644 src/net/sf/briar/android/invitation/CodeEntryWidget.java create mode 100644 src/net/sf/briar/android/invitation/CodesDoNotMatchActivity.java create mode 100644 src/net/sf/briar/android/invitation/ConfirmationCodeActivity.java create mode 100644 src/net/sf/briar/android/invitation/ConfirmationListener.java create mode 100644 src/net/sf/briar/android/invitation/ConnectionActivity.java create mode 100644 src/net/sf/briar/android/invitation/ConnectionFailedActivity.java create mode 100644 src/net/sf/briar/android/invitation/ConnectionListener.java create mode 100644 src/net/sf/briar/android/invitation/ContactAddedActivity.java create mode 100644 src/net/sf/briar/android/invitation/InvitationCodeActivity.java create mode 100644 src/net/sf/briar/android/invitation/InvitationManager.java create mode 100644 src/net/sf/briar/android/invitation/InvitationManagerFactory.java create mode 100644 src/net/sf/briar/android/invitation/InvitationManagerImpl.java create mode 100644 src/net/sf/briar/android/invitation/NetworkSetupActivity.java create mode 100644 src/net/sf/briar/android/invitation/WaitForContactActivity.java create mode 100644 src/net/sf/briar/android/invitation/WifiStateListener.java create mode 100644 src/net/sf/briar/android/invitation/WifiWidget.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e9dfd8090b..7992928960 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3,11 +3,23 @@ package="net.sf.briar" android:versionCode="1" android:versionName="1.0" > + <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="16" /> + <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.INTERNET" /> - <application android:label="@string/app_name" > + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> + <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /> + + <application + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" > + <service android:name=".HelloWorldService" android:exported="false" > + <intent-filter> + <action android:name=".HelloWorldService" /> + </intent-filter> + </service> <activity android:name=".HelloWorldActivity" android:label="@string/app_name" > @@ -16,10 +28,37 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> - <service android:name=".HelloWorldService" android:exported="false" > - <intent-filter> - <action android:name="net.sf.briar.HelloWorldService" /> - </intent-filter> - </service> + <activity + android:name=".android.invitation.NetworkSetupActivity" + android:label="@string/title" > + </activity> + <activity + android:name=".android.invitation.InvitationCodeActivity" + android:label="@string/title" > + </activity> + <activity + android:name=".android.invitation.ConnectionActivity" + android:label="@string/title" > + </activity> + <activity + android:name=".android.invitation.ConnectionFailedActivity" + android:label="@string/title" > + </activity> + <activity + android:name=".android.invitation.ConfirmationCodeActivity" + android:label="@string/title" > + </activity> + <activity + android:name=".android.invitation.WaitForContactActivity" + android:label="@string/title" > + </activity> + <activity + android:name=".android.invitation.CodesDoNotMatchActivity" + android:label="@string/title" > + </activity> + <activity + android:name=".android.invitation.ContactAddedActivity" + android:label="@string/title" > + </activity> </application> </manifest> diff --git a/res/drawable-hdpi/ic_launcher.png b/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..1b63e455be32834b8e0a9240bfaed25b5c69f5f0 GIT binary patch literal 2364 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 literal 0 HcmV?d00001 diff --git a/res/drawable-ldpi/ic_launcher.png b/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..e0119f08678c54c5efd851a1860c9a18978ec3cd GIT binary patch literal 1276 zcmV<Y1OxktP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ000ETNkl<Zc-qxi zZAe>J7*^M=9jz<1l=a7;47NenQA+X0V1u;<*PnKO>@q6oYAvi3wEk?Xvo#Ik4_jFx zmPOVrR%;TL>8g%6N4ARAFG&4NP;`PK1wR+@BPM6>b9?UP-kTe})o9s)2g1#Jp6AJX z&w1Z-5*PP>AMNe!Z%<84eKR{dYYzkhzNMulUpO2N0r-q(_-=A?G8?hm<s;tb^L@6k zu<%DP7+fK7w$VTgVlfAE!4VT99UUFVXJ%$xYinz4vjcO%0j{kWLsq_`*RY@`BYH9h zE^uzfRKm!}Na5=0>Kcpj04KPiq1%k#?=PbFA3@gl_%Zwa`gIAN7K^4Rp3CDfPd>m6 z4LzpfJ3BiK%gf7}nW@XlV&BEZN%-;fX-z{9&z@Dp{d(zAL<}^bwchKCudS{9XnJ}& z5N*xG(hxMD<#0GoL^HLkzrVju>s4)sA@SAq_4U<5TPr&$^Yine^%i7=p)+SR<La+m zVHKxNN$}jh9hDQB&{k(@cTZ2xpYrUq4>YhJp4^b|%im@}NN(t-loZz7{YVi9R5sj- zfI0^JVwRu{50aaVjEp1W<Kv17T-9u17mXiExM@AFY3RQ5nj%gwZ0@_#T7ot_NZZ_Q zw|`6hN0G{%GK2wbco56Ln;ws+fvV_hGX!mTfEO6rNA+Mxy}R69Rm^C+D8c&VrlujM z=e{CNFTgL~ZQb47et3bQ1GM$#_4KQ{%a?WSGS8hm%waG{=&GpLu+Nc)f8hm&4pRLI z>M|7LIwUs)59B2YhLXHqZ*aYWxZQ@J4G-ky5DXn^YikRr7xhjWf;OEl1EQg%#>U3c zxw*Lw4Ph<VFI<oitpckJ;fJg@pxxBe^pE(;4%lqAzvv9C2tozEYfFD+IB3`XeD0jW zP<?hbRqK33T(fMKK^q>#MZLeYwDjKK;2@J9Q`L1yFYY<6Y8tv_{Zg|IL33zmh`|HA zz|fwww6srKT3W)?=yu!?G@+fIp8h$!z|b3ncdS;ccX)W1iMwql3_%N;m6esx;emS* zMq*A*PL|v44x_K2E~vXbV5P3DhB^inSj&*>saX-%*8iK(!=MRmc#t1K(E8skFE8)v z?d`?!GHL~Wken<5tz-*FSOzU<LR)eC;LZ{a2E+O4>gtuz(NWwEwyh3<8yYn=H7n3m zXGc215{~5O=a;!$E;cqc7GWwDhQJAKXcQC_n4zh4gcY;&7U8|3qM~}I(<v-CR8g_d zZN(73C<>h5h6c2_X4IQU0#Dxug@uK+RII|(V{i?Ac_63zRa0)RgbuSg>b*=J=dG#| zIKTx?a6^M@ZFo0B0RFXjKQAxOWU*M5X(tH33^hYf6P7nk%)wl6fD4@9<{J8Mue@p= zO-)Vx+GH|$sZODQv4MdBHZd_FY}v)dMPW^ZLLmY8jA!@`F^I(+%moLyz{$B2Uip4c z*vl8)@yyK3Tq5<Cm6e4k?P!LqwY3#D2ApLC;4_}#JH#Lsb1)YioNMo9%*Yq|F8;1j zD?X<21*QFaqtW=RxVU(#q@?5pfpNURGkk{_#9|Jgo5;Ch^FI+UTp&Hn(|(L_l8{XJ mgd>?hJH}%U^Etcq8u<?*kyu0?-&{NZ0000<MNUMnLSTZ%K5K^n literal 0 HcmV?d00001 diff --git a/res/drawable-ldpi/iconic_check_alt_green.png b/res/drawable-ldpi/iconic_check_alt_green.png new file mode 100644 index 0000000000000000000000000000000000000000..0751e8d49172a3b2746ac1d442383d838586075f GIT binary patch literal 499 zcmV<P0Sx|$P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzl}SWFRCwCVm(gv*AP|Ou2{J-Qh~F#4 z*}&N#o*?gi>r3A=fwMu`z>d^+dxK^KZ_wUFXA2XI!9bLgPCSI%_j4R);LOp!e)260 z1^5m;pPANxU%}<ad(*kZ<qqH@3@7j{^D`811|gSK0s#C5LuFa5t6^435OQ-C0Pup~ z8y3fU5+N4_P|7Qo#!7ulxMAhrEUg{XOmJ<_+lXnmZAUiLgiwB{o&aaW7`Ip``<_Pz z;W3;$f;lnA44e|c_mJk&BI3^E)Zy9$@Ls7eO!?6;HxtxeQ^GfvE?Nlc?J424MZiut z6kkUk8-6cF;S!j<iwtLaAD9hH!A&B9;7bA~W)Kk!UlM>pY6_~0xWs@Dec;cxzzko| zRq!DL&BC0AOvHjCThJYjtq~CjN4uf`={R{JA_5#uathXZ1j3p)(8VPL-a%bu!znm> z{1KtQf$)*3-iYc1cY@jCgVpc#K2XwiDYf;)nl>W3qm@q(FnJ>gt=-DRA|BobulF!{ piKkh_$LXhO)m{QpKhOUK7yxF9%o==(s|)}D002ovPDHLkV1j^s*5CjD literal 0 HcmV?d00001 diff --git a/res/drawable-ldpi/iconic_x_alt_red.png b/res/drawable-ldpi/iconic_x_alt_red.png new file mode 100644 index 0000000000000000000000000000000000000000..d560b26460ba89d7cb1cb8465841b7f8d7dd639c GIT binary patch literal 552 zcmV+@0@wYCP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz%1J~)RCwCFmw}OjFc3vU#saM1=1RZ{ zJUY-0paN^Lg3y6<fL5R-+*}28pqrb|onVsPKyYU=8HSMmvdJ!+l@i+hL*>-%sBNiz zd4`>-U8ptLkGe_b%>=?Fbq8v>iZcsvB#?R%011CmX9BC0n)OOWAm6T++9PgVeN7;) zFvk^h@&Iu8iP~DFGdtG_bNc~6Y1DFN#-7lQJzv@kv|c=561zRL9cBQ4z2OdAjnI;W zU(FrN{yg*^IB?<=Miuo117Y747|TKYYHDP-Tp+Hf?*b6Lc!#kZL~gY;(yL+y{+$gE z#6TR|x)x;5okngC0#IuM5I*r%0I<zy@I4~8yM)w4aepd~@x&bQSO6!)9Pudt$t@P( z<s2~4krcpr2n8X^0-R?=K+A+ETdZi*a8t!|L7oWN#R4=OfFRU-5F9|GQN4x+mNc;u zgxUZC-;~V4ZYw+-nPS93s3(_mdE&;1_nQAzF@4k~Dndn-GOfNChoSv_c5e{xpf$_` zsN1VI01WO3dX&wYg&`_v_%k7{Qv1Z)VdvVru4&Fx49bl#OG>V0oAJuoe}Ua6oYX4z q2lJFc?Wzmky-;*JUiy0e5MTiNRMD9C*ppEJ0000<MNUMnLSTZnr}8oY literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/ic_launcher.png b/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..9873a76f01b7952e9ca72018763aa519a5b8f1e8 GIT binary patch literal 1591 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 literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/ic_launcher.png b/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..0b22fd5d7a57db85fccf364f07052262aaf8ec22 GIT binary patch literal 3192 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 literal 0 HcmV?d00001 diff --git a/res/layout/activity_add_contact.xml b/res/layout/activity_add_contact.xml new file mode 100644 index 0000000000..c37b80fec0 --- /dev/null +++ b/res/layout/activity_add_contact.xml @@ -0,0 +1,5 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/add_contact_container" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" /> diff --git a/res/layout/activity_codes_do_not_match.xml b/res/layout/activity_codes_do_not_match.xml new file mode 100644 index 0000000000..4bd1965bc9 --- /dev/null +++ b/res/layout/activity_codes_do_not_match.xml @@ -0,0 +1,5 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/codes_do_not_match_container" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" /> diff --git a/res/layout/activity_connection.xml b/res/layout/activity_connection.xml new file mode 100644 index 0000000000..367b75fc55 --- /dev/null +++ b/res/layout/activity_connection.xml @@ -0,0 +1,5 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/connection_container" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" /> \ No newline at end of file diff --git a/res/layout/activity_connection_failed.xml b/res/layout/activity_connection_failed.xml new file mode 100644 index 0000000000..9672914f4c --- /dev/null +++ b/res/layout/activity_connection_failed.xml @@ -0,0 +1,5 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/connection_failed_container" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" /> diff --git a/res/layout/activity_connection_succeeded.xml b/res/layout/activity_connection_succeeded.xml new file mode 100644 index 0000000000..0b6962125d --- /dev/null +++ b/res/layout/activity_connection_succeeded.xml @@ -0,0 +1,5 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/connection_succeeded_container" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" /> \ No newline at end of file diff --git a/res/layout/activity_contact_added.xml b/res/layout/activity_contact_added.xml new file mode 100644 index 0000000000..05a3c684f1 --- /dev/null +++ b/res/layout/activity_contact_added.xml @@ -0,0 +1,5 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/contact_added_container" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" /> diff --git a/res/layout/activity_invitation_code.xml b/res/layout/activity_invitation_code.xml new file mode 100644 index 0000000000..193e86aaf5 --- /dev/null +++ b/res/layout/activity_invitation_code.xml @@ -0,0 +1,5 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/invitation_code_container" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" /> diff --git a/res/layout/activity_network_setup.xml b/res/layout/activity_network_setup.xml new file mode 100644 index 0000000000..48d2de513f --- /dev/null +++ b/res/layout/activity_network_setup.xml @@ -0,0 +1,5 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/network_setup_container" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" /> \ No newline at end of file diff --git a/res/layout/activity_test_bluetooth.xml b/res/layout/activity_test_bluetooth.xml new file mode 100644 index 0000000000..eaf4032a4c --- /dev/null +++ b/res/layout/activity_test_bluetooth.xml @@ -0,0 +1,71 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" > + + <TextView + android:id="@+id/test_bt_screen_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Testing Bluetooth actions" + android:textAppearance="?android:attr/textAppearanceLarge" /> + + <Button + android:id="@+id/button1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Show paired devices info" + android:onClick="showBtPairedDevicesButtonClicked" /> + + <Button + android:id="@+id/test_bt_conn_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Connect bluetooh" + android:onClick="testBtConnButtonClicked" /> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" > + + <Button + android:id="@+id/test_bt_sendData_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:onClick="testBtSendDataButtonClicked" + android:text="Send data" /> + + <Button + android:id="@+id/test_bt_recvData_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:onClick="testBtReceiveDataButtonClicked" + android:text="Recive data" /> + </LinearLayout> + + <ScrollView + android:id="@+id/test_bt_log_view" + android:layout_width="fill_parent" + android:layout_height="wrap_content" > + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" > + + <TextView + android:id="@+id/test_bt_log_console_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Bluetooth actions log" /> + + <TextView + android:id="@+id/test_bt_log_console_msgs" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="actions log..." /> + + </LinearLayout> + </ScrollView> + +</LinearLayout> diff --git a/res/layout/activity_wait_for_contact.xml b/res/layout/activity_wait_for_contact.xml new file mode 100644 index 0000000000..cd96d411b2 --- /dev/null +++ b/res/layout/activity_wait_for_contact.xml @@ -0,0 +1,5 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/wait_for_contact_container" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" /> \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index eeabdb397e..0a2f6313df 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1,4 +1,40 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Briar</string> + <string name="menu_settings">Settings</string> + <string name="title">Add a Contact</string> + <string name="welcome">Welcome to Briar! Add a contact to get started.</string> + <string name="add_contact_button">Add a contact</string> + <string name="face_to_face">For security reasons you must be face to face with someone to add them as a contact.</string> + <string name="same_network">Briar can add contacts via Wi-Fi or Bluetooth. To use Wi-Fi you must both be connected to the same network.</string> + <string name="wifi_not_available">Wi-Fi is not available on this device.</string> + <string name="wifi_disabled">Wi-Fi is OFF.</string> + <string name="turn_on_wifi_button">Turn on Wi-Fi</string> + <string name="wifi_disconnected">Wi-Fi is DISCONNECTED.</string> + <string name="connect_to_wifi_button">Connect to Wi-Fi</string> + <string name="wifi_connected">Wi-Fi is CONNECTED to %1$s.</string> + <string name="bluetooth_not_available">Bluetooth is not available on this device.</string> + <string name="bluetooth_disabled">Bluetooth is OFF.</string> + <string name="turn_on_bluetooth_button">Turn on Bluetooth</string> + <string name="bluetooth_not_discoverable">Bluetooth is NOT DISCOVERABLE.</string> + <string name="make_bluetooth_discoverable_button">Make Bluetooth discoverable</string> + <string name="bluetooth_enabled">Bluetooth is ON.</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="connecting_wifi">Connecting via %1$s\u2026</string> + <string name="connecting_bluetooth">Connecting via Bluetooth\u2026</string> + <string name="connection_failed">Connection failed.</string> + <string name="check_same_network">Please check that you are both using the same network.</string> + <string name="try_again_button">Try again</string> + <string name="connected_to_contact">Connected to contact.</string> + <string name="your_confirmation_code">Your confirmation code is</string> + <string name="enter_confirmation_code">Please enter your contact\'s confirmation code:</string> + <string name="waiting_for_contact">Waiting for contact\u2026</string> + <string name="codes_do_not_match">Codes do not match!</string> + <string name="interfering">This could mean that someone is trying to interfere with your connection.</string> + <string name="contact_added">Contact added.</string> + <string name="enter_nickname">Please enter a nickname for this contact:</string> + <string name="add_another_contact_button">Add another contact</string> + <string name="done_button">Done</string> </resources> diff --git a/src/net/sf/briar/HelloWorldActivity.java b/src/net/sf/briar/HelloWorldActivity.java index 53607532d3..76868cb806 100644 --- a/src/net/sf/briar/HelloWorldActivity.java +++ b/src/net/sf/briar/HelloWorldActivity.java @@ -1,19 +1,41 @@ package net.sf.briar; +import net.sf.briar.android.invitation.NetworkSetupActivity; import android.app.Activity; import android.content.Intent; import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.LinearLayout; import android.widget.TextView; -public class HelloWorldActivity extends Activity { +public class HelloWorldActivity extends Activity implements OnClickListener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - TextView text = new TextView(this); - text.setText("Hello world"); - setContentView(text); + setContentView(R.layout.activity_add_contact); + LinearLayout layout = (LinearLayout) findViewById( + R.id.add_contact_container); + + TextView welcome = new TextView(this); + welcome.setText(R.string.welcome); + layout.addView(welcome); + Button addContact = new Button(this); + addContact.setText(R.string.add_contact_button); + addContact.setOnClickListener(this); + layout.addView(addContact); + TextView faceToFace = new TextView(this); + faceToFace.setText(R.string.face_to_face); + layout.addView(faceToFace); + Intent intent = new Intent("net.sf.briar.HelloWorldService"); startService(intent); } + + public void onClick(View view) { + startActivity(new Intent(this, NetworkSetupActivity.class)); + finish(); + } } diff --git a/src/net/sf/briar/android/invitation/BluetoothStateListener.java b/src/net/sf/briar/android/invitation/BluetoothStateListener.java new file mode 100644 index 0000000000..fa7846c7c4 --- /dev/null +++ b/src/net/sf/briar/android/invitation/BluetoothStateListener.java @@ -0,0 +1,6 @@ +package net.sf.briar.android.invitation; + +interface BluetoothStateListener { + + void bluetoothStateChanged(boolean enabled); +} diff --git a/src/net/sf/briar/android/invitation/BluetoothWidget.java b/src/net/sf/briar/android/invitation/BluetoothWidget.java new file mode 100644 index 0000000000..e97d7d86e9 --- /dev/null +++ b/src/net/sf/briar/android/invitation/BluetoothWidget.java @@ -0,0 +1,71 @@ +package net.sf.briar.android.invitation; + +import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; +import static android.provider.Settings.ACTION_BLUETOOTH_SETTINGS; +import static android.view.Gravity.CENTER_HORIZONTAL; +import net.sf.briar.R; +import android.bluetooth.BluetoothAdapter; +import android.content.Context; +import android.content.Intent; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class BluetoothWidget extends LinearLayout implements OnClickListener { + + private BluetoothStateListener listener = null; + + public BluetoothWidget(Context ctx) { + super(ctx); + } + + void init(BluetoothStateListener listener) { + this.listener = listener; + setOrientation(VERTICAL); + setPadding(0, 10, 0, 10); + populate(); + } + + void populate() { + removeAllViews(); + Context ctx = getContext(); + TextView status = new TextView(ctx); + status.setGravity(CENTER_HORIZONTAL); + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + if(adapter == null) { + bluetoothStateChanged(false); + status.setText(R.string.bluetooth_not_available); + addView(status); + } else if(adapter.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE) { + bluetoothStateChanged(true); + status.setText(R.string.bluetooth_enabled); + addView(status); + } else if(adapter.isEnabled()) { + bluetoothStateChanged(false); + status.setText(R.string.bluetooth_not_discoverable); + addView(status); + Button turnOn = new Button(ctx); + turnOn.setText(R.string.make_bluetooth_discoverable_button); + turnOn.setOnClickListener(this); + addView(turnOn); + } else { + bluetoothStateChanged(false); + status.setText(R.string.bluetooth_disabled); + addView(status); + Button turnOn = new Button(ctx); + turnOn.setText(R.string.turn_on_bluetooth_button); + turnOn.setOnClickListener(this); + addView(turnOn); + } + } + + private void bluetoothStateChanged(boolean enabled) { + listener.bluetoothStateChanged(enabled); + } + + public void onClick(View view) { + getContext().startActivity(new Intent(ACTION_BLUETOOTH_SETTINGS)); + } +} diff --git a/src/net/sf/briar/android/invitation/CodeEntryListener.java b/src/net/sf/briar/android/invitation/CodeEntryListener.java new file mode 100644 index 0000000000..1a8f7b3d8d --- /dev/null +++ b/src/net/sf/briar/android/invitation/CodeEntryListener.java @@ -0,0 +1,6 @@ +package net.sf.briar.android.invitation; + +interface CodeEntryListener { + + void codeEntered(String code); +} diff --git a/src/net/sf/briar/android/invitation/CodeEntryWidget.java b/src/net/sf/briar/android/invitation/CodeEntryWidget.java new file mode 100644 index 0000000000..5565782753 --- /dev/null +++ b/src/net/sf/briar/android/invitation/CodeEntryWidget.java @@ -0,0 +1,76 @@ +package net.sf.briar.android.invitation; + +import static android.text.InputType.TYPE_CLASS_NUMBER; +import static android.view.Gravity.CENTER; +import static android.view.Gravity.CENTER_HORIZONTAL; +import net.sf.briar.R; +import android.content.Context; +import android.view.KeyEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; + +public class CodeEntryWidget extends LinearLayout implements +OnEditorActionListener, OnClickListener { + + private CodeEntryListener listener = null; + private EditText codeEntry = null; + + public CodeEntryWidget(Context ctx) { + super(ctx); + } + + void init(CodeEntryListener listener, String prompt) { + this.listener = listener; + setOrientation(VERTICAL); + + Context ctx = getContext(); + TextView enterCode = new TextView(ctx); + enterCode.setGravity(CENTER_HORIZONTAL); + enterCode.setText(prompt); + addView(enterCode); + + final Button continueButton = new Button(ctx); + continueButton.setText(R.string.continue_button); + continueButton.setEnabled(false); + continueButton.setOnClickListener(this); + + codeEntry = new EditText(ctx) { + @Override + protected void onTextChanged(CharSequence text, int start, + int lengthBefore, int lengthAfter) { + continueButton.setEnabled(text.length() == 6); + } + }; + codeEntry.setOnEditorActionListener(this); + codeEntry.setMinEms(5); + codeEntry.setMaxEms(5); + codeEntry.setMaxLines(1); + codeEntry.setInputType(TYPE_CLASS_NUMBER); + + LinearLayout innerLayout = new LinearLayout(ctx); + innerLayout.setOrientation(HORIZONTAL); + innerLayout.setGravity(CENTER); + innerLayout.addView(codeEntry); + innerLayout.addView(continueButton); + addView(innerLayout); + } + + public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) { + validateAndReturnCode(); + return true; + } + + public void onClick(View view) { + validateAndReturnCode(); + } + + private void validateAndReturnCode() { + CharSequence code = codeEntry.getText(); + if(code.length() == 6) listener.codeEntered(code.toString()); + } +} diff --git a/src/net/sf/briar/android/invitation/CodesDoNotMatchActivity.java b/src/net/sf/briar/android/invitation/CodesDoNotMatchActivity.java new file mode 100644 index 0000000000..c981bc0670 --- /dev/null +++ b/src/net/sf/briar/android/invitation/CodesDoNotMatchActivity.java @@ -0,0 +1,54 @@ +package net.sf.briar.android.invitation; + +import static android.view.Gravity.CENTER; +import static android.widget.LinearLayout.HORIZONTAL; +import net.sf.briar.R; +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +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; + +public class CodesDoNotMatchActivity extends Activity +implements OnClickListener { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_codes_do_not_match); + LinearLayout outerLayout = (LinearLayout) findViewById( + R.id.codes_do_not_match_container); + + LinearLayout innerLayout = new LinearLayout(this); + innerLayout.setOrientation(HORIZONTAL); + innerLayout.setGravity(CENTER); + ImageView icon = new ImageView(this); + icon.setImageResource(R.drawable.iconic_x_alt_red); + icon.setPadding(10, 10, 10, 10); + innerLayout.addView(icon); + TextView failed = new TextView(this); + failed.setTextSize(20); + failed.setText(R.string.codes_do_not_match); + innerLayout.addView(failed); + outerLayout.addView(innerLayout); + + TextView interfering = new TextView(this); + interfering.setText(R.string.interfering); + outerLayout.addView(interfering); + Button tryAgain = new Button(this); + tryAgain.setText(R.string.try_again_button); + tryAgain.setOnClickListener(this); + outerLayout.addView(tryAgain); + } + + public void onClick(View view) { + Intent intent = new Intent(this, InvitationCodeActivity.class); + intent.putExtras(getIntent().getExtras()); + startActivity(intent); + finish(); + } +} diff --git a/src/net/sf/briar/android/invitation/ConfirmationCodeActivity.java b/src/net/sf/briar/android/invitation/ConfirmationCodeActivity.java new file mode 100644 index 0000000000..e4bb901df0 --- /dev/null +++ b/src/net/sf/briar/android/invitation/ConfirmationCodeActivity.java @@ -0,0 +1,69 @@ +package net.sf.briar.android.invitation; + +import static android.view.Gravity.CENTER; +import static android.view.Gravity.CENTER_HORIZONTAL; +import static android.widget.LinearLayout.HORIZONTAL; +import net.sf.briar.R; +import android.app.Activity; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Bundle; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class ConfirmationCodeActivity extends Activity +implements CodeEntryListener { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_connection_succeeded); + LinearLayout outerLayout = (LinearLayout) findViewById( + R.id.connection_succeeded_container); + + LinearLayout innerLayout = new LinearLayout(this); + innerLayout.setOrientation(HORIZONTAL); + innerLayout.setGravity(CENTER); + ImageView icon = new ImageView(this); + icon.setImageResource(R.drawable.iconic_check_alt_green); + icon.setPadding(10, 10, 10, 10); + innerLayout.addView(icon); + TextView failed = new TextView(this); + failed.setTextSize(20); + failed.setText(R.string.connected_to_contact); + innerLayout.addView(failed); + outerLayout.addView(innerLayout); + + TextView checkNetwork = new TextView(this); + checkNetwork.setGravity(CENTER_HORIZONTAL); + checkNetwork.setText(R.string.your_confirmation_code); + outerLayout.addView(checkNetwork); + TextView code = new TextView(this); + code.setGravity(CENTER_HORIZONTAL); + InvitationManager im = InvitationManagerFactory.getInvitationManager(); + String localConfirmationCode = im.getLocalConfirmationCode(); + code.setText(localConfirmationCode); + code.setTextSize(50); + outerLayout.addView(code); + CodeEntryWidget codeEntry = new CodeEntryWidget(this); + Resources res = getResources(); + codeEntry.init(this, res.getString(R.string.enter_confirmation_code)); + outerLayout.addView(codeEntry); + } + + public void codeEntered(String code) { + InvitationManager im = InvitationManagerFactory.getInvitationManager(); + String remoteConfirmationCode = im.getRemoteConfirmationCode(); + if(code.equals(String.valueOf(remoteConfirmationCode))) { + Intent intent = new Intent(this, WaitForContactActivity.class); + intent.putExtras(getIntent().getExtras()); + startActivity(intent); + } else { + Intent intent = new Intent(this, CodesDoNotMatchActivity.class); + intent.putExtras(getIntent().getExtras()); + startActivity(intent); + } + finish(); + } +} diff --git a/src/net/sf/briar/android/invitation/ConfirmationListener.java b/src/net/sf/briar/android/invitation/ConfirmationListener.java new file mode 100644 index 0000000000..af2024676a --- /dev/null +++ b/src/net/sf/briar/android/invitation/ConfirmationListener.java @@ -0,0 +1,8 @@ +package net.sf.briar.android.invitation; + +interface ConfirmationListener { + + void confirmationReceived(); + + void confirmationNotReceived(); +} diff --git a/src/net/sf/briar/android/invitation/ConnectionActivity.java b/src/net/sf/briar/android/invitation/ConnectionActivity.java new file mode 100644 index 0000000000..2564adf002 --- /dev/null +++ b/src/net/sf/briar/android/invitation/ConnectionActivity.java @@ -0,0 +1,99 @@ +package net.sf.briar.android.invitation; + +import static android.view.Gravity.CENTER; +import static android.view.Gravity.CENTER_HORIZONTAL; +import static android.widget.LinearLayout.HORIZONTAL; +import net.sf.briar.R; +import android.app.Activity; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Bundle; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +public class ConnectionActivity extends Activity implements ConnectionListener { + + private final InvitationManager manager = + InvitationManagerFactory.getInvitationManager(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_connection); + LinearLayout outerLayout = (LinearLayout) findViewById( + R.id.connection_container); + + Bundle b = getIntent().getExtras(); + String networkName = b.getString( + "net.sf.briar.android.invitation.NETWORK_NAME"); + boolean useBluetooth = b.getBoolean( + "net.sf.briar.android.invitation.USE_BLUETOOTH"); + + TextView yourCode = new TextView(this); + yourCode.setGravity(CENTER_HORIZONTAL); + yourCode.setText(R.string.your_invitation_code); + outerLayout.addView(yourCode); + TextView code = new TextView(this); + code.setGravity(CENTER_HORIZONTAL); + code.setText(manager.getLocalInvitationCode()); + code.setTextSize(50); + outerLayout.addView(code); + + if(networkName != null) { + LinearLayout innerLayout = new LinearLayout(this); + innerLayout.setOrientation(HORIZONTAL); + innerLayout.setGravity(CENTER); + ProgressBar progress = new ProgressBar(this); + progress.setIndeterminate(true); + progress.setPadding(0, 10, 10, 0); + innerLayout.addView(progress); + TextView connecting = new TextView(this); + Resources res = getResources(); + String text = res.getString(R.string.connecting_wifi); + text = String.format(text, networkName); + connecting.setText(text); + innerLayout.addView(connecting); + outerLayout.addView(innerLayout); + manager.startWifiConnectionWorker(this); + } + + if(useBluetooth) { + LinearLayout innerLayout = new LinearLayout(this); + innerLayout.setOrientation(HORIZONTAL); + innerLayout.setGravity(CENTER); + ProgressBar progress = new ProgressBar(this); + progress.setPadding(0, 10, 10, 0); + progress.setIndeterminate(true); + innerLayout.addView(progress); + TextView connecting = new TextView(this); + connecting.setText(R.string.connecting_bluetooth); + innerLayout.addView(connecting); + outerLayout.addView(innerLayout); + manager.startBluetoothConnectionWorker(this); + } + + manager.tryToConnect(this); + } + + public void connectionEstablished() { + final Intent intent = new Intent(this, ConfirmationCodeActivity.class); + intent.putExtras(getIntent().getExtras()); + runOnUiThread(new Runnable() { + public void run() { + startActivity(intent); + finish(); + } + }); + } + + public void connectionNotEstablished() { + final Intent intent = new Intent(this, ConnectionFailedActivity.class); + runOnUiThread(new Runnable() { + public void run() { + startActivity(intent); + finish(); + } + }); + } +} diff --git a/src/net/sf/briar/android/invitation/ConnectionFailedActivity.java b/src/net/sf/briar/android/invitation/ConnectionFailedActivity.java new file mode 100644 index 0000000000..0b868a1740 --- /dev/null +++ b/src/net/sf/briar/android/invitation/ConnectionFailedActivity.java @@ -0,0 +1,96 @@ +package net.sf.briar.android.invitation; + +import static android.view.Gravity.CENTER; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static android.widget.LinearLayout.HORIZONTAL; +import net.sf.briar.R; +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +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; + +public class ConnectionFailedActivity extends Activity +implements WifiStateListener, BluetoothStateListener, OnClickListener { + + private WifiWidget wifi = null; + private BluetoothWidget bluetooth = null; + private Button tryAgainButton = null; + private String networkName = null; + private boolean useBluetooth = false; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_connection_failed); + LinearLayout outerLayout = (LinearLayout) findViewById( + R.id.connection_failed_container); + + LinearLayout innerLayout = new LinearLayout(this); + innerLayout.setOrientation(HORIZONTAL); + innerLayout.setGravity(CENTER); + ImageView icon = new ImageView(this); + icon.setImageResource(R.drawable.iconic_x_alt_red); + icon.setPadding(10, 10, 10, 10); + innerLayout.addView(icon); + TextView failed = new TextView(this); + failed.setTextSize(20); + failed.setText(R.string.connection_failed); + innerLayout.addView(failed); + outerLayout.addView(innerLayout); + + TextView checkNetwork = new TextView(this); + checkNetwork.setText(R.string.check_same_network); + outerLayout.addView(checkNetwork); + wifi = new WifiWidget(this); + wifi.init(this); + outerLayout.addView(wifi); + bluetooth = new BluetoothWidget(this); + bluetooth.init(this); + outerLayout.addView(bluetooth); + tryAgainButton = new Button(this); + tryAgainButton.setText(R.string.try_again_button); + tryAgainButton.setOnClickListener(this); + setTryAgainButtonVisibility(); + outerLayout.addView(tryAgainButton); + } + + @Override + public void onResume() { + super.onResume(); + wifi.populate(); + bluetooth.populate(); + } + + public void wifiStateChanged(String networkName) { + this.networkName = networkName; + setTryAgainButtonVisibility(); + } + + public void bluetoothStateChanged(boolean enabled) { + useBluetooth = enabled; + setTryAgainButtonVisibility(); + } + + private void setTryAgainButtonVisibility() { + if(tryAgainButton == null) return; + if(useBluetooth || networkName != null) + tryAgainButton.setVisibility(VISIBLE); + else tryAgainButton.setVisibility(INVISIBLE); + } + + public void onClick(View view) { + Intent intent = new Intent(this, InvitationCodeActivity.class); + intent.putExtra("net.sf.briar.android.invitation.NETWORK_NAME", + networkName); + intent.putExtra("net.sf.briar.android.invitation.USE_BLUETOOTH", + useBluetooth); + startActivity(intent); + finish(); + } +} diff --git a/src/net/sf/briar/android/invitation/ConnectionListener.java b/src/net/sf/briar/android/invitation/ConnectionListener.java new file mode 100644 index 0000000000..a1bc643dc3 --- /dev/null +++ b/src/net/sf/briar/android/invitation/ConnectionListener.java @@ -0,0 +1,8 @@ +package net.sf.briar.android.invitation; + +interface ConnectionListener { + + void connectionEstablished(); + + void connectionNotEstablished(); +} diff --git a/src/net/sf/briar/android/invitation/ContactAddedActivity.java b/src/net/sf/briar/android/invitation/ContactAddedActivity.java new file mode 100644 index 0000000000..846c25bf1a --- /dev/null +++ b/src/net/sf/briar/android/invitation/ContactAddedActivity.java @@ -0,0 +1,91 @@ +package net.sf.briar.android.invitation; + +import static android.view.Gravity.CENTER; +import static android.view.Gravity.CENTER_HORIZONTAL; +import static android.widget.LinearLayout.HORIZONTAL; +import net.sf.briar.R; +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; + +public class ContactAddedActivity extends Activity implements OnClickListener, +OnEditorActionListener { + + private volatile Button done = null; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_contact_added); + LinearLayout outerLayout = (LinearLayout) findViewById( + R.id.contact_added_container); + + LinearLayout innerLayout = new LinearLayout(this); + innerLayout.setOrientation(HORIZONTAL); + innerLayout.setGravity(CENTER); + ImageView icon = new ImageView(this); + icon.setImageResource(R.drawable.iconic_check_alt_green); + icon.setPadding(10, 10, 10, 10); + innerLayout.addView(icon); + TextView failed = new TextView(this); + failed.setTextSize(20); + failed.setText(R.string.contact_added); + innerLayout.addView(failed); + outerLayout.addView(innerLayout); + + TextView enterNickname = new TextView(this); + enterNickname.setGravity(CENTER_HORIZONTAL); + enterNickname.setText(R.string.enter_nickname); + outerLayout.addView(enterNickname); + final Button addAnother = new Button(this); + final Button done = new Button(this); + this.done = done; + EditText nicknameEntry = new EditText(this) { + @Override + protected void onTextChanged(CharSequence text, int start, + int lengthBefore, int lengthAfter) { + addAnother.setEnabled(text.length() > 0); + done.setEnabled(text.length() > 0); + } + }; + nicknameEntry.setMinEms(10); + nicknameEntry.setMaxEms(20); + nicknameEntry.setMaxLines(1); + nicknameEntry.setOnEditorActionListener(this); + outerLayout.addView(nicknameEntry); + + innerLayout = new LinearLayout(this); + innerLayout.setOrientation(HORIZONTAL); + innerLayout.setGravity(CENTER); + addAnother.setText(R.string.add_another_contact_button); + addAnother.setEnabled(false); + addAnother.setOnClickListener(this); + innerLayout.addView(addAnother); + done.setText(R.string.done_button); + done.setEnabled(false); + done.setOnClickListener(this); + innerLayout.addView(done); + outerLayout.addView(innerLayout); + } + + public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) { + if(textView.getText().length() > 0) finish(); + return true; + } + + public void onClick(View view) { + if(done == null) return; + if(view != done) + startActivity(new Intent(this, NetworkSetupActivity.class)); + finish(); + } +} diff --git a/src/net/sf/briar/android/invitation/InvitationCodeActivity.java b/src/net/sf/briar/android/invitation/InvitationCodeActivity.java new file mode 100644 index 0000000000..79e7a22cd9 --- /dev/null +++ b/src/net/sf/briar/android/invitation/InvitationCodeActivity.java @@ -0,0 +1,48 @@ +package net.sf.briar.android.invitation; + +import static android.view.Gravity.CENTER_HORIZONTAL; +import net.sf.briar.R; +import android.app.Activity; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Bundle; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class InvitationCodeActivity extends Activity +implements CodeEntryListener { + + private final InvitationManager manager = + InvitationManagerFactory.getInvitationManager(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_invitation_code); + LinearLayout layout = (LinearLayout) findViewById( + R.id.invitation_code_container); + + TextView yourCode = new TextView(this); + yourCode.setGravity(CENTER_HORIZONTAL); + yourCode.setText(R.string.your_invitation_code); + layout.addView(yourCode); + TextView code = new TextView(this); + code.setGravity(CENTER_HORIZONTAL); + String localInvitationCode = manager.getLocalInvitationCode(); + code.setText(localInvitationCode); + code.setTextSize(50); + layout.addView(code); + CodeEntryWidget codeEntry = new CodeEntryWidget(this); + Resources res = getResources(); + codeEntry.init(this, res.getString(R.string.enter_invitation_code)); + layout.addView(codeEntry); + } + + public void codeEntered(String code) { + manager.setRemoteInvitationCode(code); + Intent intent = new Intent(this, ConnectionActivity.class); + intent.putExtras(getIntent().getExtras()); + startActivity(intent); + finish(); + } +} diff --git a/src/net/sf/briar/android/invitation/InvitationManager.java b/src/net/sf/briar/android/invitation/InvitationManager.java new file mode 100644 index 0000000000..f77baa4c33 --- /dev/null +++ b/src/net/sf/briar/android/invitation/InvitationManager.java @@ -0,0 +1,26 @@ +package net.sf.briar.android.invitation; + +import android.content.Context; + +interface InvitationManager { + + int TIMEOUT = 20 * 1000; + + void tryToConnect(ConnectionListener listener); + + String getLocalInvitationCode(); + + String getRemoteInvitationCode(); + + void setRemoteInvitationCode(String code); + + void startWifiConnectionWorker(Context ctx); + + void startBluetoothConnectionWorker(Context ctx); + + String getLocalConfirmationCode(); + + String getRemoteConfirmationCode(); + + void startConfirmationWorker(ConfirmationListener listener); +} diff --git a/src/net/sf/briar/android/invitation/InvitationManagerFactory.java b/src/net/sf/briar/android/invitation/InvitationManagerFactory.java new file mode 100644 index 0000000000..a38ac435ad --- /dev/null +++ b/src/net/sf/briar/android/invitation/InvitationManagerFactory.java @@ -0,0 +1,14 @@ +package net.sf.briar.android.invitation; + +class InvitationManagerFactory { + + private static final Object LOCK = new Object(); + private static InvitationManager instance = null; // Locking: lock + + static InvitationManager getInvitationManager() { + synchronized(LOCK) { + if(instance == null) instance = new InvitationManagerImpl(); + return instance; + } + } +} diff --git a/src/net/sf/briar/android/invitation/InvitationManagerImpl.java b/src/net/sf/briar/android/invitation/InvitationManagerImpl.java new file mode 100644 index 0000000000..c5afcacec1 --- /dev/null +++ b/src/net/sf/briar/android/invitation/InvitationManagerImpl.java @@ -0,0 +1,67 @@ +package net.sf.briar.android.invitation; + +import android.content.Context; +import android.util.Log; + +class InvitationManagerImpl implements InvitationManager { + + public void tryToConnect(final ConnectionListener listener) { + new Thread() { + @Override + public void run() { + try { + // FIXME + Thread.sleep((long) (Math.random() * TIMEOUT)); + if(Math.random() < 0.5) listener.connectionEstablished(); + else listener.connectionNotEstablished(); + } catch(InterruptedException e) { + Log.w(getClass().getName(), e.toString()); + listener.connectionNotEstablished(); + } + } + }.start(); + } + + public String getLocalInvitationCode() { + // FIXME + return "123456"; + } + + public String getRemoteInvitationCode() { + // FIXME + return "123456"; + } + + public void setRemoteInvitationCode(String code) { + // FIXME + } + + public void startWifiConnectionWorker(Context ctx) { + // FIXME + } + + public void startBluetoothConnectionWorker(Context ctx) { + // FIXME + } + + public String getLocalConfirmationCode() { + // FIXME + return "123456"; + } + + public String getRemoteConfirmationCode() { + // FIXME + return "123456"; + } + + public void startConfirmationWorker(ConfirmationListener listener) { + // FIXME + try { + Thread.sleep(1000 + (int) (Math.random() * 4 * 1000)); + } catch(InterruptedException e) { + Log.w(getClass().getName(), e.toString()); + Thread.currentThread().interrupt(); + } + listener.confirmationReceived(); + } +} diff --git a/src/net/sf/briar/android/invitation/NetworkSetupActivity.java b/src/net/sf/briar/android/invitation/NetworkSetupActivity.java new file mode 100644 index 0000000000..2488e4d125 --- /dev/null +++ b/src/net/sf/briar/android/invitation/NetworkSetupActivity.java @@ -0,0 +1,88 @@ +package net.sf.briar.android.invitation; + +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import net.sf.briar.R; +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class NetworkSetupActivity extends Activity +implements WifiStateListener, BluetoothStateListener, OnClickListener { + + private WifiWidget wifi = null; + private BluetoothWidget bluetooth = null; + private Button continueButton = null; + private String networkName = null; + private boolean useBluetooth = false; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_network_setup); + LinearLayout layout = (LinearLayout) findViewById( + R.id.network_setup_container); + + TextView sameNetwork = new TextView(this); + sameNetwork.setText(R.string.same_network); + layout.addView(sameNetwork); + wifi = new WifiWidget(this); + wifi.init(this); + layout.addView(wifi); + bluetooth = new BluetoothWidget(this); + bluetooth.init(this); + layout.addView(bluetooth); + continueButton = new Button(this); + continueButton.setText(R.string.continue_button); + continueButton.setOnClickListener(this); + setContinueButtonVisibility(); + layout.addView(continueButton); + } + + @Override + public void onResume() { + super.onResume(); + wifi.populate(); + bluetooth.populate(); + } + + public void wifiStateChanged(final String name) { + runOnUiThread(new Runnable() { + public void run() { + networkName = name; + setContinueButtonVisibility(); + } + }); + } + + public void bluetoothStateChanged(final boolean enabled) { + runOnUiThread(new Runnable() { + public void run() { + useBluetooth = enabled; + setContinueButtonVisibility(); + } + }); + } + + private void setContinueButtonVisibility() { + if(continueButton == null) return; + if(useBluetooth || networkName != null) + continueButton.setVisibility(VISIBLE); + else continueButton.setVisibility(INVISIBLE); + } + + public void onClick(View view) { + Intent intent = new Intent(this, InvitationCodeActivity.class); + intent.putExtra("net.sf.briar.android.invitation.NETWORK_NAME", + networkName); + intent.putExtra("net.sf.briar.android.invitation.USE_BLUETOOTH", + useBluetooth); + startActivity(intent); + finish(); + } +} diff --git a/src/net/sf/briar/android/invitation/WaitForContactActivity.java b/src/net/sf/briar/android/invitation/WaitForContactActivity.java new file mode 100644 index 0000000000..ed778ff23f --- /dev/null +++ b/src/net/sf/briar/android/invitation/WaitForContactActivity.java @@ -0,0 +1,76 @@ +package net.sf.briar.android.invitation; + +import static android.view.Gravity.CENTER; +import static android.view.Gravity.CENTER_HORIZONTAL; +import static android.widget.LinearLayout.HORIZONTAL; +import net.sf.briar.R; +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +public class WaitForContactActivity extends Activity +implements ConfirmationListener { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_wait_for_contact); + LinearLayout outerLayout = (LinearLayout) findViewById( + R.id.wait_for_contact_container); + + LinearLayout innerLayout = new LinearLayout(this); + innerLayout.setOrientation(HORIZONTAL); + innerLayout.setGravity(CENTER); + ImageView icon = new ImageView(this); + icon.setImageResource(R.drawable.iconic_check_alt_green); + icon.setPadding(10, 10, 10, 10); + innerLayout.addView(icon); + TextView failed = new TextView(this); + failed.setTextSize(20); + failed.setText(R.string.connected_to_contact); + innerLayout.addView(failed); + outerLayout.addView(innerLayout); + + TextView yourCode = new TextView(this); + yourCode.setGravity(CENTER_HORIZONTAL); + yourCode.setText(R.string.your_confirmation_code); + outerLayout.addView(yourCode); + TextView code = new TextView(this); + code.setGravity(CENTER_HORIZONTAL); + InvitationManager im = InvitationManagerFactory.getInvitationManager(); + String localConfirmationCode = im.getLocalConfirmationCode(); + code.setText(localConfirmationCode); + code.setTextSize(50); + outerLayout.addView(code); + + innerLayout = new LinearLayout(this); + innerLayout.setOrientation(HORIZONTAL); + innerLayout.setGravity(CENTER); + ProgressBar progress = new ProgressBar(this); + progress.setIndeterminate(true); + progress.setPadding(0, 10, 10, 0); + innerLayout.addView(progress); + TextView connecting = new TextView(this); + connecting.setText(R.string.waiting_for_contact); + innerLayout.addView(connecting); + outerLayout.addView(innerLayout); + + im.startConfirmationWorker(this); + } + + public void confirmationReceived() { + startActivity(new Intent(this, ContactAddedActivity.class)); + finish(); + } + + public void confirmationNotReceived() { + Intent intent = new Intent(this, CodesDoNotMatchActivity.class); + intent.putExtras(getIntent().getExtras()); + startActivity(intent); + finish(); + } +} diff --git a/src/net/sf/briar/android/invitation/WifiStateListener.java b/src/net/sf/briar/android/invitation/WifiStateListener.java new file mode 100644 index 0000000000..c668b0d2d3 --- /dev/null +++ b/src/net/sf/briar/android/invitation/WifiStateListener.java @@ -0,0 +1,6 @@ +package net.sf.briar.android.invitation; + +interface WifiStateListener { + + void wifiStateChanged(String networkName); +} diff --git a/src/net/sf/briar/android/invitation/WifiWidget.java b/src/net/sf/briar/android/invitation/WifiWidget.java new file mode 100644 index 0000000000..d27d6e8b3a --- /dev/null +++ b/src/net/sf/briar/android/invitation/WifiWidget.java @@ -0,0 +1,77 @@ +package net.sf.briar.android.invitation; + +import static android.content.Context.WIFI_SERVICE; +import static android.provider.Settings.ACTION_WIFI_SETTINGS; +import static android.view.Gravity.CENTER_HORIZONTAL; +import net.sf.briar.R; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.net.wifi.WifiManager; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class WifiWidget extends LinearLayout implements OnClickListener { + + private WifiStateListener listener = null; + + public WifiWidget(Context ctx) { + super(ctx); + } + + void init(WifiStateListener listener) { + this.listener = listener; + setOrientation(VERTICAL); + setPadding(0, 10, 0, 0); + populate(); + } + + void populate() { + removeAllViews(); + Context ctx = getContext(); + TextView status = new TextView(ctx); + status.setGravity(CENTER_HORIZONTAL); + WifiManager wifi = (WifiManager) ctx.getSystemService(WIFI_SERVICE); + if(wifi == null) { + wifiStateChanged(null); + status.setText(R.string.wifi_not_available); + addView(status); + } else if(wifi.isWifiEnabled()) { + String networkName = wifi.getConnectionInfo().getSSID(); + if(networkName == null) { + wifiStateChanged(null); + status.setText(R.string.wifi_disconnected); + addView(status); + Button connect = new Button(ctx); + connect.setText(R.string.connect_to_wifi_button); + connect.setOnClickListener(this); + addView(connect); + } else { + wifiStateChanged(networkName); + Resources res = getResources(); + String connected = res.getString(R.string.wifi_connected); + status.setText(String.format(connected, networkName)); + addView(status); + } + } else { + wifiStateChanged(null); + status.setText(R.string.wifi_disabled); + addView(status); + Button connect = new Button(ctx); + connect.setText(R.string.connect_to_wifi_button); + connect.setOnClickListener(this); + addView(connect); + } + } + + private void wifiStateChanged(String networkName) { + if(listener != null) listener.wifiStateChanged(networkName); + } + + public void onClick(View view) { + getContext().startActivity(new Intent(ACTION_WIFI_SETTINGS)); + } +} -- GitLab