diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9a4e65c45..bd8c9df7c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -153,6 +153,12 @@
android:value="org.thoughtcrime.securesms.ConversationListActivity" />
+
+
activityRule = TestUtils.getOfflineActivityRule();
+
+ @Before
+ public void createChats() {
+ DcContext dcContext = DcHelper.getContext(getInstrumentation().getTargetContext());
+ dcContext.createChatByContactId(DcContact.DC_CONTACT_ID_SELF);
+ // Disable bcc_self so that DC doesn't try to send messages to the server.
+ // If we didn't do this, messages would stay in DC_STATE_OUT_PENDING forever.
+ // The thing is, DC_STATE_OUT_PENDING show a rotating circle animation, and Espresso doesn't work
+ // with animations, and the tests would hang and never finish.
+ dcContext.setConfig("bcc_self", "0");
+ activityRule.getScenario().onActivity(a -> createdGroupId = DcHelper.getContext(a).createGroupChat(false, "group"));
+ }
+
+ @After
+ public void cleanup() {
+ TestUtils.cleanup();
+ }
+
+ @Test
+ public void testSimpleForwarding() {
+ // Open device talk
+ // The group is at position 0, self chat is at position 1, device talk is at position 2
+ onView(withId(R.id.list)).perform(RecyclerViewActions.actionOnItemAtPosition(2, click()));
+ onView(withId(R.id.title)).check(matches(withText(R.string.device_talk)));
+ onView(withId(android.R.id.list)).perform(RecyclerViewActions.actionOnItemAtPosition(0, longClick()));
+ onView(withId(R.id.menu_context_forward)).perform(click());
+ // Send it to self chat (which is sorted to the top because we're forwarding)
+ onView(withId(R.id.list)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
+
+ onView(withId(R.id.title)).check(matches(withText(R.string.device_talk)));
+
+ pressBack();
+
+ onView(withId(R.id.toolbar_title)).check(matches(withText(R.string.connectivity_not_connected)));
+ // Self chat moved up because we sent a message there
+ onView(withId(R.id.list)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
+ onView(withId(R.id.title)).check(matches(withText(R.string.saved_messages)));
+ onView(withId(android.R.id.list)).perform(RecyclerViewActions.actionOnItemAtPosition(0, longClick()));
+ onView(withId(R.id.menu_context_forward)).perform(click());
+ // Send it to the group
+ onView(withId(R.id.list)).perform(RecyclerViewActions.actionOnItemAtPosition(1, click()));
+ onView(withText(android.R.string.ok)).perform(click());
+ onView(withId(R.id.title)).check(matches(withText("group")));
+
+ pressBack();
+ onView(withId(R.id.title)).check(matches(withText(R.string.saved_messages)));
+
+ pressBack();
+ onView(withId(R.id.toolbar_title)).check(matches(withText(R.string.connectivity_not_connected)));
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/ConversationFragment.java b/src/org/thoughtcrime/securesms/ConversationFragment.java
index cd7419ccc..e585b58c9 100644
--- a/src/org/thoughtcrime/securesms/ConversationFragment.java
+++ b/src/org/thoughtcrime/securesms/ConversationFragment.java
@@ -16,6 +16,9 @@
*/
package org.thoughtcrime.securesms;
+import static com.b44t.messenger.DcContact.DC_CONTACT_ID_SELF;
+import static org.thoughtcrime.securesms.util.RelayUtil.setForwardingMessageIds;
+
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
@@ -77,10 +80,6 @@ import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
-import static com.b44t.messenger.DcContact.DC_CONTACT_ID_SELF;
-import static org.thoughtcrime.securesms.util.RelayUtil.REQUEST_RELAY;
-import static org.thoughtcrime.securesms.util.RelayUtil.setForwardingMessageIds;
-
@SuppressLint("StaticFieldLeak")
public class ConversationFragment extends MessageSelectorFragment
{
@@ -453,10 +452,10 @@ public class ConversationFragment extends MessageSelectorFragment
}
private void handleForwardMessage(final Set messageRecords) {
- Intent composeIntent = new Intent(getActivity(), ConversationListActivity.class);
+ Intent composeIntent = new Intent();
int[] msgIds = DcMsg.msgSetToIds(messageRecords);
setForwardingMessageIds(composeIntent, msgIds);
- startActivityForResult(composeIntent, REQUEST_RELAY);
+ ConversationListRelayingActivity.start(this, composeIntent);
getActivity().overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out);
}
diff --git a/src/org/thoughtcrime/securesms/ConversationListRelayingActivity.java b/src/org/thoughtcrime/securesms/ConversationListRelayingActivity.java
new file mode 100644
index 000000000..a4e74b50f
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/ConversationListRelayingActivity.java
@@ -0,0 +1,37 @@
+package org.thoughtcrime.securesms;
+
+import static org.thoughtcrime.securesms.util.RelayUtil.REQUEST_RELAY;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+
+import androidx.fragment.app.Fragment;
+
+/**
+ * "Relaying" means "Forwarding or Sharing".
+ *
+ * When forwarding or sharing, we show the ConversationListActivity to the user.
+ * However, ConversationListActivity has `launchMode="singleTask"`, which means that this will
+ * destroy the existing ConversationListActivity.
+ *
+ * In API 20-29, `startActivityForResult()` could be used instead of `startActivity()`
+ * to override this behavior and get two instances of ConversationListActivity.
+ *
+ * As this is not possible anymore starting with API 30, we needed another solution, and created
+ * this activity here.
+ *
+ * See https://github.com/deltachat/deltachat-android/issues/1704.
+ */
+
+public class ConversationListRelayingActivity extends ConversationListActivity {
+ public static void start(Fragment fragment, Intent intent) {
+ intent.setComponent(new ComponentName(fragment.getContext(), ConversationListRelayingActivity.class));
+ fragment.startActivityForResult(intent, REQUEST_RELAY);
+ }
+
+ public static void start(Activity activity, Intent intent) {
+ intent.setComponent(new ComponentName(activity, ConversationListRelayingActivity.class));
+ activity.startActivityForResult(intent, REQUEST_RELAY);
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/ShareActivity.java b/src/org/thoughtcrime/securesms/ShareActivity.java
index 2797e5d04..99ae50f62 100644
--- a/src/org/thoughtcrime/securesms/ShareActivity.java
+++ b/src/org/thoughtcrime/securesms/ShareActivity.java
@@ -17,7 +17,6 @@
package org.thoughtcrime.securesms;
-import static org.thoughtcrime.securesms.util.RelayUtil.REQUEST_RELAY;
import static org.thoughtcrime.securesms.util.RelayUtil.setSharedText;
import android.Manifest;
@@ -263,11 +262,13 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity implement
if (chatId != -1) {
composeIntent = getBaseShareIntent(ConversationActivity.class);
composeIntent.putExtra(EXTRA_CHAT_ID, chatId);
+ RelayUtil.setSharedUris(composeIntent, resolvedExtras);
+ startActivity(composeIntent);
} else {
- composeIntent = getBaseShareIntent(ConversationListActivity.class);
+ composeIntent = getBaseShareIntent(ConversationListRelayingActivity.class);
+ RelayUtil.setSharedUris(composeIntent, resolvedExtras);
+ ConversationListRelayingActivity.start(this, composeIntent);
}
- RelayUtil.setSharedUris(composeIntent, resolvedExtras);
- startActivityForResult(composeIntent, REQUEST_RELAY);
// We use startActivityForResult() here so that the conversations list is correctly updated. (hide "Device messages", ...)a
// With startActivity() the list was not always updated before and after sharing and incorrectly showed or did not show the device talk.
finish();