diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml index 8be1cbf4d..0afef62b0 100644 --- a/briar-android/src/main/AndroidManifest.xml +++ b/briar-android/src/main/AndroidManifest.xml @@ -1,28 +1,36 @@ + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools"> - - - + + + - - - - - - + + + + + + + - - - - + + + + + - - + + + tools:ignore="GoogleAppIndexingWarning" + tools:targetApi="16"> + android:label="@string/app_name" + android:theme="@style/BriarTheme.NoActionBar"> @@ -95,20 +104,32 @@ + android:launchMode="singleTask" + android:theme="@style/BriarTheme.NoActionBar"> + + + + + + + + + + + + + + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/> + android:value="org.briarproject.briar.android.privategroup.conversation.GroupActivity"/> + android:value="org.briarproject.briar.android.privategroup.conversation.GroupActivity"/> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/> + android:value="org.briarproject.briar.android.conversation.ConversationActivity"/> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/> + android:value="org.briarproject.briar.android.forum.ForumActivity"/> + android:value="org.briarproject.briar.android.blog.BlogActivity"/> + android:value="org.briarproject.briar.android.blog.BlogActivity"/> + android:value="org.briarproject.briar.android.blog.BlogActivity"/> + android:value="org.briarproject.briar.android.blog.BlogActivity"/> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/> + android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity" + android:theme="@style/BriarTheme.NoActionBar"> @@ -338,8 +344,7 @@ android:windowSoftInputMode="stateHidden|adjustResize"> + android:value="org.briarproject.briar.android.conversation.ConversationActivity"/> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/> @@ -368,8 +372,7 @@ android:parentActivityName="org.briarproject.briar.android.settings.SettingsActivity"> + android:value="org.briarproject.briar.android.settings.SettingsActivity"/> + android:value="org.briarproject.briar.android.settings.SettingsActivity"/> + android:value="org.briarproject.briar.android.settings.SettingsActivity"/> - - - - - - - - - - - - - - + android:windowSoftInputMode="stateHidden|adjustResize"/> blogCounts = new Multiset<>(); private int contactAddedTotal = 0; private int nextRequestId = 0; + @Nullable private ContactId blockedContact = null; + @Nullable private GroupId blockedGroup = null; private boolean blockSignInReminder = false; private boolean blockBlogs = false; @@ -325,9 +329,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, } else { // Touching the notification shows the contact list Intent i = new Intent(appContext, NavDrawerActivity.class); - i.putExtra(INTENT_CONTACTS, true); i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); - i.setData(Uri.parse(CONTACT_URI)); + i.setData(CONTACT_URI); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(NavDrawerActivity.class); t.addNextIntent(i); @@ -363,9 +366,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, return defaults; } - private void setDeleteIntent(BriarNotificationBuilder b, String uri) { + private void setDeleteIntent(BriarNotificationBuilder b, Uri uri) { Intent i = new Intent(appContext, NotificationCleanupService.class); - i.setData(Uri.parse(uri)); + i.setData(uri); b.setDeleteIntent(PendingIntent.getService(appContext, nextRequestId++, i, 0)); } @@ -425,9 +428,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, } else { // Touching the notification shows the group list Intent i = new Intent(appContext, NavDrawerActivity.class); - i.putExtra(INTENT_GROUPS, true); i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); - i.setData(Uri.parse(GROUP_URI)); + i.setData(GROUP_URI); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(NavDrawerActivity.class); t.addNextIntent(i); @@ -493,9 +495,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, } else { // Touching the notification shows the forum list Intent i = new Intent(appContext, NavDrawerActivity.class); - i.putExtra(INTENT_FORUMS, true); i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); - i.setData(Uri.parse(FORUM_URI)); + i.setData(FORUM_URI); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(NavDrawerActivity.class); t.addNextIntent(i); @@ -546,9 +547,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, setDeleteIntent(b, BLOG_URI); // Touching the notification shows the combined blog feed Intent i = new Intent(appContext, NavDrawerActivity.class); - i.putExtra(INTENT_BLOGS, true); i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); - i.setData(Uri.parse(BLOG_URI)); + i.setData(BLOG_URI); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(NavDrawerActivity.class); t.addNextIntent(i); @@ -585,9 +585,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, setDeleteIntent(b, CONTACT_ADDED_URI); // Touching the notification shows the contact list Intent i = new Intent(appContext, NavDrawerActivity.class); - i.putExtra(INTENT_CONTACTS, true); i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); - i.setData(Uri.parse(CONTACT_URI)); + i.setData(CONTACT_URI); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(NavDrawerActivity.class); t.addNextIntent(i); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/NotificationCleanupService.java b/briar-android/src/main/java/org/briarproject/briar/android/NotificationCleanupService.java index 44698d3f5..1d8ca912f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/NotificationCleanupService.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/NotificationCleanupService.java @@ -2,17 +2,18 @@ package org.briarproject.briar.android; import android.app.IntentService; import android.content.Intent; +import android.net.Uri; import android.support.annotation.Nullable; import org.briarproject.briar.api.android.AndroidNotificationManager; import javax.inject.Inject; -import static org.briarproject.briar.api.android.AndroidNotificationManager.BLOG_URI; -import static org.briarproject.briar.api.android.AndroidNotificationManager.CONTACT_URI; -import static org.briarproject.briar.api.android.AndroidNotificationManager.FORUM_URI; -import static org.briarproject.briar.api.android.AndroidNotificationManager.GROUP_URI; -import static org.briarproject.briar.api.android.AndroidNotificationManager.CONTACT_ADDED_URI; +import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.BLOG_URI; +import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.CONTACT_ADDED_URI; +import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.CONTACT_URI; +import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.FORUM_URI; +import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.GROUP_URI; public class NotificationCleanupService extends IntentService { @@ -37,7 +38,7 @@ public class NotificationCleanupService extends IntentService { @Override protected void onHandleIntent(@Nullable Intent i) { if (i == null || i.getData() == null) return; - String uri = i.getData().toString(); + Uri uri = i.getData(); if (uri.equals(CONTACT_URI)) { notificationManager.clearAllContactNotifications(); } else if (uri.equals(GROUP_URI)) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java index 8f476d456..5315abb6a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java @@ -12,11 +12,11 @@ import android.widget.CheckBox; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; +import org.briarproject.briar.android.account.UnlockActivity; import org.briarproject.briar.android.controller.BriarController; import org.briarproject.briar.android.controller.DbController; import org.briarproject.briar.android.controller.handler.UiResultHandler; import org.briarproject.briar.android.login.StartupActivity; -import org.briarproject.briar.android.account.UnlockActivity; import org.briarproject.briar.android.logout.ExitActivity; import org.briarproject.briar.api.android.LockManager; @@ -66,9 +66,9 @@ public abstract class BriarActivity extends BaseActivity { @Nullable Intent data) { super.onActivityResult(request, result, data); if (request == REQUEST_PASSWORD) { - // The result can be RESULT_CANCELED if there's no account + // We get RESULT_CANCELED when the account gets deleted or + // StartupActivity finishes before entering the password. if (result == RESULT_OK) briarController.startAndBindService(); - else finish(); } else if (request == REQUEST_UNLOCK && result != RESULT_OK) { // We arrive here, if the user presses 'back' // in the Keyguard unlock screen, because UnlockActivity finishes. diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/remote/AddContactActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/remote/AddContactActivity.java index b04358016..8650c8233 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/remote/AddContactActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/remote/AddContactActivity.java @@ -57,9 +57,9 @@ public class AddContactActivity extends BriarActivity implements }); Intent i = getIntent(); - if (i != null) { + if (state == null) { + // do not react to the intent again when recreating the activity onNewIntent(i); - setIntent(null); // don't keep the intent for configuration changes } if (state == null) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/IntentRouter.java b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/IntentRouter.java new file mode 100644 index 000000000..6e6682f1a --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/IntentRouter.java @@ -0,0 +1,39 @@ +package org.briarproject.briar.android.navdrawer; + +import android.content.Context; +import android.content.Intent; + +import org.briarproject.briar.android.activity.BriarActivity; +import org.briarproject.briar.android.contact.add.remote.AddContactActivity; + +import static android.content.Intent.ACTION_SEND; +import static android.content.Intent.ACTION_VIEW; +import static android.content.Intent.EXTRA_TEXT; +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; +import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.LINK_REGEX; + +class IntentRouter { + + static void handleExternalIntent(Context ctx, Intent i) { + String action = i.getAction(); + // add remote contact with clicked briar:// link + if (ACTION_VIEW.equals(action) && "briar".equals(i.getScheme())) { + redirect(ctx, i, AddContactActivity.class); + } + // add remote contact with shared briar:// link + else if (ACTION_SEND.equals(action) && + "text/plain".equals(i.getType()) && + i.getStringExtra(EXTRA_TEXT) != null && + LINK_REGEX.matcher(i.getStringExtra(EXTRA_TEXT)).find()) { + redirect(ctx, i, AddContactActivity.class); + } + } + + private static void redirect(Context ctx, Intent i, + Class activityClass) { + i.setClass(ctx, activityClass); + i.addFlags(FLAG_ACTIVITY_CLEAR_TOP); + ctx.startActivity(i); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java index a9901acf4..78f5fbb17 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java @@ -3,6 +3,7 @@ package org.briarproject.briar.android.navdrawer; import android.annotation.SuppressLint; import android.content.Intent; import android.content.res.Configuration; +import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -60,9 +61,11 @@ import static android.support.v4.widget.DrawerLayout.LOCK_MODE_LOCKED_CLOSED; import static android.view.View.GONE; import static android.view.View.VISIBLE; import static java.util.Objects.requireNonNull; +import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING; import static org.briarproject.briar.android.BriarService.EXTRA_STARTUP_FAILED; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PASSWORD; +import static org.briarproject.briar.android.navdrawer.IntentRouter.handleExternalIntent; import static org.briarproject.briar.android.navdrawer.NavDrawerController.ExpiryWarning.NO; import static org.briarproject.briar.android.navdrawer.NavDrawerController.ExpiryWarning.UPDATE; import static org.briarproject.briar.android.util.UiUtils.getDaysUntilExpiry; @@ -73,14 +76,21 @@ public class NavDrawerActivity extends BriarActivity implements BaseFragmentListener, TransportStateListener, OnNavigationItemSelectedListener { - public static final String INTENT_CONTACTS = "intent_contacts"; - public static final String INTENT_GROUPS = "intent_groups"; - public static final String INTENT_FORUMS = "intent_forums"; - public static final String INTENT_BLOGS = "intent_blogs"; - public static final String INTENT_SIGN_OUT = "intent_sign_out"; - private static final Logger LOG = - Logger.getLogger(NavDrawerActivity.class.getName()); + getLogger(NavDrawerActivity.class.getName()); + + public static Uri CONTACT_URI = + Uri.parse("briar-content://org.briarproject.briar/contact"); + public static Uri GROUP_URI = + Uri.parse("briar-content://org.briarproject.briar/group"); + public static Uri FORUM_URI = + Uri.parse("briar-content://org.briarproject.briar/forum"); + public static Uri BLOG_URI = + Uri.parse("briar-content://org.briarproject.briar/blog"); + public static Uri CONTACT_ADDED_URI = + Uri.parse("briar-content://org.briarproject.briar/contact/added"); + public static Uri SIGN_OUT_URI = + Uri.parse("briar-content://org.briarproject.briar/sign-out"); private ActionBarDrawerToggle drawerToggle; @@ -95,26 +105,6 @@ public class NavDrawerActivity extends BriarActivity implements private List transports; private BaseAdapter transportsAdapter; - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - exitIfStartupFailed(intent); - // TODO don't create new instances if they are on the stack (#606) - if (intent.getBooleanExtra(INTENT_GROUPS, false)) { - startFragment(GroupListFragment.newInstance(), R.id.nav_btn_groups); - } else if (intent.getBooleanExtra(INTENT_FORUMS, false)) { - startFragment(ForumListFragment.newInstance(), R.id.nav_btn_forums); - } else if (intent.getBooleanExtra(INTENT_CONTACTS, false)) { - startFragment(ContactListFragment.newInstance(), - R.id.nav_btn_contacts); - } else if (intent.getBooleanExtra(INTENT_BLOGS, false)) { - startFragment(FeedFragment.newInstance(), R.id.nav_btn_blogs); - } else if (intent.getBooleanExtra(INTENT_SIGN_OUT, false)) { - signOut(false, false); - } - setIntent(null); - } - @Override public void injectActivity(ActivityComponent component) { component.inject(this); @@ -153,7 +143,8 @@ public class NavDrawerActivity extends BriarActivity implements startFragment(ContactListFragment.newInstance(), R.id.nav_btn_contacts); } - if (getIntent() != null) { + if (state == null) { + // do not call this again when there's existing state onNewIntent(getIntent()); } } @@ -190,6 +181,37 @@ public class NavDrawerActivity extends BriarActivity implements } } + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + // will call System.exit() + exitIfStartupFailed(intent); + + if ("briar-content".equals(intent.getScheme())) { + handleContentIntent(intent); + } else { + handleExternalIntent(this, intent); + } + } + + private void handleContentIntent(Intent intent) { + Uri uri = intent.getData(); + // TODO don't create new instances if they are on the stack (#606) + if (CONTACT_URI.equals(uri) || CONTACT_ADDED_URI.equals(uri)) { + startFragment(ContactListFragment.newInstance(), + R.id.nav_btn_contacts); + } else if (GROUP_URI.equals(uri)) { + startFragment(GroupListFragment.newInstance(), R.id.nav_btn_groups); + } else if (FORUM_URI.equals(uri)) { + startFragment(ForumListFragment.newInstance(), R.id.nav_btn_forums); + } else if (BLOG_URI.equals(uri)) { + startFragment(FeedFragment.newInstance(), R.id.nav_btn_blogs); + } else if (SIGN_OUT_URI.equals(uri)) { + signOut(false, false); + } + } + private void exitIfStartupFailed(Intent intent) { if (intent.getBooleanExtra(EXTRA_STARTUP_FAILED, false)) { finish(); @@ -325,7 +347,6 @@ public class NavDrawerActivity extends BriarActivity implements if (item != null) item.setVisible(visible); } - @SuppressWarnings("ConstantConditions") private void showExpiryWarning(ExpiryWarning expiry) { int daysUntilExpiry = getDaysUntilExpiry(); if (daysUntilExpiry < 0) signOut(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java index 6f5dcacc4..b87e0e4cb 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java @@ -79,10 +79,10 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_ONLY_WHE import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.now; -import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD; import static org.briarproject.briar.android.BriarApplication.ENTRY_ACTIVITY; +import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_RINGTONE; -import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_SIGN_OUT; +import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.SIGN_OUT_URI; import static org.briarproject.briar.android.util.UiUtils.hasScreenLock; import static org.briarproject.briar.android.util.UiUtils.triggerFeedback; import static org.briarproject.briar.api.android.AndroidNotificationManager.BLOG_CHANNEL_ID; @@ -578,7 +578,7 @@ public class SettingsFragment extends PreferenceFragmentCompat language.setValue(newValue); Intent intent = new Intent(getContext(), ENTRY_ACTIVITY); intent.setFlags(FLAG_ACTIVITY_CLEAR_TOP); - intent.putExtra(INTENT_SIGN_OUT, true); + intent.setData(SIGN_OUT_URI); requireActivity().startActivity(intent); requireActivity().finish(); }); diff --git a/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java b/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java index 0a4951155..eec2b8e9f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java +++ b/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java @@ -43,13 +43,6 @@ public interface AndroidNotificationManager { String FAILURE_CHANNEL_ID = "zStartupFailure"; String REMINDER_CHANNEL_ID = "zSignInReminder"; - // Content URIs for pending intents - String CONTACT_URI = "content://org.briarproject.briar/contact"; - String GROUP_URI = "content://org.briarproject.briar/group"; - String FORUM_URI = "content://org.briarproject.briar/forum"; - String BLOG_URI = "content://org.briarproject.briar/blog"; - String CONTACT_ADDED_URI = "content://org.briarproject.briar/contact/added"; - // Actions for pending intents String ACTION_DISMISS_REMINDER = "dismissReminder";