diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml index 82d4b83cfca31940105b2a64a3b4b57544bba5b8..be1d305ff9e0e0daf9587d61a881096d4248d8da 100644 --- a/briar-android/src/main/AndroidManifest.xml +++ b/briar-android/src/main/AndroidManifest.xml @@ -3,19 +3,26 @@ package="org.briarproject.briar" xmlns:android="http://schemas.android.com/apk/res/android"> - <uses-feature android:name="android.hardware.bluetooth" android:required="false"/> - <uses-feature android:name="android.hardware.camera" android:required="false"/> - <uses-feature android:name="android.hardware.touchscreen" android:required="false" /> - - <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> - <uses-permission android:name="android.permission.BLUETOOTH" /> - <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> - <uses-permission android:name="android.permission.CAMERA" /> - <uses-permission android:name="android.permission.INTERNET" /> - <uses-permission android:name="android.permission.VIBRATE" /> - <uses-permission android:name="android.permission.WAKE_LOCK" /> + <uses-feature + android:name="android.hardware.bluetooth" + android:required="false"/> + <uses-feature + android:name="android.hardware.camera" + android:required="false"/> + <uses-feature + android:name="android.hardware.touchscreen" + android:required="false"/> + + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> + <uses-permission android:name="android.permission.BLUETOOTH"/> + <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> + <uses-permission android:name="android.permission.CAMERA"/> + <uses-permission android:name="android.permission.INTERNET"/> + <uses-permission android:name="android.permission.VIBRATE"/> + <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> + <uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/> <application @@ -78,8 +85,8 @@ <activity android:name="org.briarproject.briar.android.splash.SplashScreenActivity" - android:theme="@style/BriarTheme.NoActionBar" - android:label="@string/app_name"> + android:label="@string/app_name" + android:theme="@style/BriarTheme.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> @@ -93,15 +100,15 @@ <activity android:name="org.briarproject.briar.android.navdrawer.NavDrawerActivity" - android:theme="@style/BriarTheme.NoActionBar" - android:launchMode="singleTop"> + android:launchMode="singleTop" + android:theme="@style/BriarTheme.NoActionBar"> </activity> <activity android:name="org.briarproject.briar.android.contact.ConversationActivity" android:label="@string/app_name" - android:theme="@style/BriarTheme.NoActionBar" android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity" + android:theme="@style/BriarTheme.NoActionBar" android:windowSoftInputMode="stateHidden|adjustResize"> <meta-data android:name="android.support.PARENT_ACTIVITY" @@ -141,7 +148,7 @@ android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/> </activity> - <activity + <activity android:name="org.briarproject.briar.android.privategroup.memberlist.GroupMemberListActivity" android:label="@string/groups_member_list" android:parentActivityName="org.briarproject.briar.android.privategroup.conversation.GroupActivity" @@ -313,13 +320,34 @@ <activity android:name="org.briarproject.briar.android.keyagreement.ContactExchangeActivity" android:label="@string/add_contact_title" - android:theme="@style/BriarTheme.NoActionBar" - android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"> + android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity" + android:theme="@style/BriarTheme.NoActionBar"> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/> </activity> + <activity + android:name="org.briarproject.briar.android.keyagreement.MailboxExchangeActivity" + android:label="@string/mailbox_add" + android:parentActivityName="org.briarproject.briar.android.settings.SettingsActivity" + android:theme="@style/BriarTheme.NoActionBar"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value="org.briarproject.briar.android.settings.SettingsActivity"/> + </activity> + + + <activity + android:name="org.briarproject.briar.android.repeater.RepeaterActivity" + android:label="@string/mailbox" + android:parentActivityName="org.briarproject.briar.android.settings.SettingsActivity" + android:theme="@style/BriarTheme.NoActionBar"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value="org.briarproject.briar.android.settings.SettingsActivity"/> + </activity> + <activity android:name="org.briarproject.briar.android.introduction.IntroductionActivity" android:label="@string/introduction_activity_title" diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java index 771a2ad57082cbf5ae82f9d0113136e1fcc03bbc..853718a926ad3f24ffb953aca9912f94e3b4dd5f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java @@ -7,6 +7,7 @@ import org.briarproject.bramble.account.BriarAccountModule; import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.contact.ContactExchangeTask; import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.api.db.DatabaseExecutor; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java index c327d64aeeddd3499efd8538afe537c1d9694ff6..7cbb170a18ef804764b43424f05418d6c8980369 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java @@ -31,6 +31,7 @@ import org.briarproject.briar.android.keyagreement.ContactExchangeErrorFragment; import org.briarproject.briar.android.keyagreement.IntroFragment; import org.briarproject.briar.android.keyagreement.KeyAgreementActivity; import org.briarproject.briar.android.keyagreement.KeyAgreementFragment; +import org.briarproject.briar.android.keyagreement.MailboxExchangeActivity; import org.briarproject.briar.android.login.AuthorNameFragment; import org.briarproject.briar.android.login.ChangePasswordActivity; import org.briarproject.briar.android.login.DozeFragment; @@ -59,6 +60,7 @@ import org.briarproject.briar.android.privategroup.memberlist.GroupMemberModule; import org.briarproject.briar.android.privategroup.reveal.GroupRevealModule; import org.briarproject.briar.android.privategroup.reveal.RevealContactsActivity; import org.briarproject.briar.android.privategroup.reveal.RevealContactsFragment; +import org.briarproject.briar.android.repeater.RepeaterActivity; import org.briarproject.briar.android.settings.SettingsActivity; import org.briarproject.briar.android.settings.SettingsFragment; import org.briarproject.briar.android.sharing.BlogInvitationActivity; @@ -105,10 +107,14 @@ public interface ActivityComponent { void inject(ContactExchangeActivity activity); + void inject(MailboxExchangeActivity activity); + void inject(KeyAgreementActivity activity); void inject(ConversationActivity activity); + void inject(RepeaterActivity activity); + void inject(ForumInvitationActivity activity); void inject(BlogInvitationActivity activity); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/MailboxExchangeActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/MailboxExchangeActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..b1763fead111fb3fa3ac1b0afa314ac9e8992c1c --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/MailboxExchangeActivity.java @@ -0,0 +1,137 @@ +package org.briarproject.briar.android.keyagreement; + +import android.os.Bundle; +import android.support.annotation.UiThread; +import android.widget.Toast; + +import org.briarproject.bramble.api.contact.ContactExchangeListener; +import org.briarproject.bramble.api.contact.ContactExchangeTask; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; +import org.briarproject.bramble.api.keyagreement.KeyAgreementResult; +import org.briarproject.briar.R; +import org.briarproject.briar.android.activity.ActivityComponent; + +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static android.widget.Toast.LENGTH_LONG; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.api.contact.ContactType.MAILBOX_OWNER; +import static org.briarproject.bramble.api.contact.ContactType.PRIVATE_MAILBOX; +import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.briar.R.string; + +public class MailboxExchangeActivity extends KeyAgreementActivity implements + ContactExchangeListener { + + private static final Logger LOG = + Logger.getLogger(MailboxExchangeActivity.class.getName()); + + @Inject + volatile ContactExchangeTask contactExchangeTask; + @Inject + volatile IdentityManager identityManager; + + @Override + public void onCreate(@Nullable Bundle state) { + super.onCreate(state); + getSupportActionBar().setTitle(string.mailbox_add); + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + protected void startContactExchange(KeyAgreementResult result) { + runOnDbThread(() -> { + LocalAuthor localAuthor; + // Load the local pseudonym + try { + localAuthor = identityManager.getLocalAuthor(); + } catch (DbException e) { + logException(LOG, WARNING, e); + contactExchangeFailed(); + return; + } + + // Exchange contact details + contactExchangeTask.startExchange(MailboxExchangeActivity.this, + localAuthor, result.getMasterKey(), + result.getConnection(), result.getTransportId(), + result.wasAlice(), MAILBOX_OWNER, PRIVATE_MAILBOX); + }); + } + + @Override + public void contactExchangeSucceeded(Author remoteAuthor) { + runOnUiThreadUnlessDestroyed(() -> { + Toast.makeText(MailboxExchangeActivity.this, + string.mailbox_paired, LENGTH_LONG) + .show(); + supportFinishAfterTransition(); + }); + } + + @Override + public void duplicateContact(Author remoteAuthor) { + runOnUiThreadUnlessDestroyed(() -> { + Toast.makeText(MailboxExchangeActivity.this, + string.mailbox_already_paired, LENGTH_LONG) + .show(); + finish(); + }); + } + + @Override + public void contactExchangeFailed() { + runOnUiThreadUnlessDestroyed(() -> { + Toast.makeText(MailboxExchangeActivity.this, + string.contact_exchange_failed, LENGTH_LONG).show(); + finish(); + }); + } + + @UiThread + @Override + public void keyAgreementFailed() { + // TODO show failure somewhere persistent? + Toast.makeText(this, R.string.connection_failed, + LENGTH_LONG).show(); + } + + @UiThread + @Override + public String keyAgreementWaiting() { + return getString(R.string.waiting_for_contact_to_scan); + } + + @UiThread + @Override + public String keyAgreementStarted() { + return getString(R.string.authenticating_with_device); + } + + @UiThread + @Override + public void keyAgreementAborted(boolean remoteAborted) { + // TODO show abort somewhere persistent? + Toast.makeText(this, + remoteAborted ? R.string.connection_aborted_remote : + R.string.connection_aborted_local, LENGTH_LONG) + .show(); + } + + @UiThread + @Override + public String keyAgreementFinished(KeyAgreementResult result) { + startContactExchange(result); + return getString(string.exchanging_contact_details); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/repeater/RepeaterActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/repeater/RepeaterActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..f26e7af852857f6e552e69674bcb14395bb759eb --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/repeater/RepeaterActivity.java @@ -0,0 +1,96 @@ +package org.briarproject.briar.android.repeater; + + +import android.os.Bundle; +import android.support.v7.widget.Toolbar; +import android.widget.TextView; + +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.db.DatabaseExecutor; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.briar.R; +import org.briarproject.briar.android.activity.ActivityComponent; +import org.briarproject.briar.android.activity.BriarActivity; + +import java.util.Collection; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import de.hdodenhof.circleimageview.CircleImageView; + +import static android.support.v4.view.ViewCompat.setTransitionName; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.api.contact.ContactType.PRIVATE_MAILBOX; +import static org.briarproject.bramble.util.LogUtils.logException; + +public class RepeaterActivity extends BriarActivity { + + private static final Logger LOG = + Logger.getLogger(RepeaterActivity.class.getName()); + @Inject + @DatabaseExecutor + Executor databaseExecutor; + @Inject + ContactManager contactManager; + + private Toolbar toolbar; + private CircleImageView toolbarAvatar; + private TextView toolbarTitle; + + @SuppressWarnings("ConstantConditions") + @Override + public void onCreate(@Nullable Bundle state) { + setSceneTransitionAnimation(); + super.onCreate(state); + + setContentView(R.layout.activity_repeater); + // Custom Toolbar + toolbar = setUpCustomToolbar(true); + if (toolbar != null) { + toolbarAvatar = toolbar.findViewById(R.id.contactAvatar); + toolbarTitle = toolbar.findViewById(R.id.repeaterName); + } + + setTransitionName(toolbarAvatar, "avatarRepeater"); + } + + @Override + public void onStart() { + super.onStart(); + loadRepeater(); + } + + private void loadRepeater() { + databaseExecutor.execute(() -> { + try { + Collection<Contact> repeaters = + contactManager.getContactsByType(PRIVATE_MAILBOX); + if (repeaters.size() > 1) + throw new IllegalStateException( + "More than one repeater found"); + if (repeaters.isEmpty()) + displayRepeater(null); + displayRepeater(repeaters.iterator().next()); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + private void displayRepeater(@Nullable Contact repeater) { + runOnUiThreadUnlessDestroyed(() -> { + // TODO: Repeater Image + toolbarAvatar.setImageResource(R.mipmap.ic_launcher_round); + toolbarTitle.setText(repeater.getAuthor().getName()); + }); + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } +} diff --git a/briar-android/src/main/res/layout/activity_repeater.xml b/briar-android/src/main/res/layout/activity_repeater.xml new file mode 100644 index 0000000000000000000000000000000000000000..a7fd5a60f186f345fb767e82faf947ee00da5c43 --- /dev/null +++ b/briar-android/src/main/res/layout/activity_repeater.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + 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" + android:orientation="vertical" + tools:context=".android.repeater.RepeaterActivity"> + + <android.support.design.widget.AppBarLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <android.support.v7.widget.Toolbar + android:id="@+id/toolbar" + style="@style/BriarToolbar" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="match_parent"> + + <include layout="@layout/repeater_avatar_status"/> + + <org.thoughtcrime.securesms.components.emoji.EmojiTextView + android:id="@+id/repeaterName" + style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse" + android:textColor="@color/action_bar_text" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_marginLeft="@dimen/margin_medium" + android:layout_marginStart="@dimen/margin_medium" + android:gravity="center" + tools:text="Contact Name"/> + + </LinearLayout> + + </android.support.v7.widget.Toolbar> + + </android.support.design.widget.AppBarLayout> +</LinearLayout> \ No newline at end of file diff --git a/briar-android/src/main/res/layout/repeater_avatar_status.xml b/briar-android/src/main/res/layout/repeater_avatar_status.xml new file mode 100644 index 0000000000000000000000000000000000000000..0d47e786e6451d0231a944b4e81da7827fb220c2 --- /dev/null +++ b/briar-android/src/main/res/layout/repeater_avatar_status.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="32dp" + android:layout_height="32dp" + tools:showIn="@layout/activity_conversation"> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/contactAvatar" + style="@style/BriarAvatar" + android:layout_width="30dp" + android:layout_height="30dp" + app:civ_border_color="@color/action_bar_text" + tools:src="@mipmap/ic_launcher_round"/> + + <ImageView + android:id="@+id/contactStatus" + android:layout_width="15dp" + android:layout_height="15dp" + android:layout_gravity="bottom|right" + android:scaleType="fitCenter" + tools:ignore="ContentDescription" + tools:src="@drawable/contact_online"/> + +</FrameLayout> \ No newline at end of file diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index bdc04d7926923e84b0577bdc1b982e347dbfe1dc..bda751e60391000df0a900b7deaf63d5b42a3c83 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -478,4 +478,10 @@ <string name="lock_is_locked">Briar is locked</string> <string name="lock_tap_to_unlock">Tap to unlock</string> + <!-- Mailbox --> + <string name="mailbox">Mailbox</string> + <string name="mailbox_add">Add Mailbox</string> + <string name="mailbox_paired">Successfully paired with mailbox</string> + <string name="mailbox_already_paired">Already paired with this mailbox</string> + <string name="mailbox_info">Show mailbox</string> </resources> diff --git a/briar-android/src/main/res/xml/settings.xml b/briar-android/src/main/res/xml/settings.xml index f325934e97334374e649d108a1cbabbd76f3580b..1326a7c05b64c8428bb4568a851bba160698ba37 100644 --- a/briar-android/src/main/res/xml/settings.xml +++ b/briar-android/src/main/res/xml/settings.xml @@ -19,7 +19,7 @@ android:key="pref_key_theme" android:summary="%s" android:title="@string/pref_theme_title"/> - + </PreferenceCategory> <PreferenceCategory @@ -167,6 +167,28 @@ </PreferenceCategory> + <PreferenceCategory + android:layout="@layout/preferences_category" + android:title="@string/mailbox"> + + <Preference + android:key="pref_key_repeater" + android:title="@string/mailbox_add"> + + <intent + android:targetClass="org.briarproject.briar.android.keyagreement.MailboxExchangeActivity" + android:targetPackage="@string/app_package"/> + </Preference> + <Preference + android:key="pref_key_repeater_list" + android:title="@string/mailbox_info"> + + <intent + android:targetClass="org.briarproject.briar.android.repeater.RepeaterActivity" + android:targetPackage="@string/app_package"/> + </Preference> + </PreferenceCategory> + <PreferenceCategory android:layout="@layout/preferences_category" android:title="@string/feedback_settings_title"/>