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