Recreate fragment whenever we handle onNewIntent instead of restarting whole activity.

This commit is contained in:
Alex Hart 2022-07-19 12:49:28 -03:00 committed by Cody Henthorne
parent 88b895f5ea
commit 8767f775e9
4 changed files with 79 additions and 108 deletions

View file

@ -32,14 +32,27 @@ open class ConversationActivity : PassphraseRequiredActivity(), ConversationPare
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
setContentView(R.layout.conversation_parent_fragment_container) setContentView(R.layout.conversation_parent_fragment_container)
if (savedInstanceState == null) {
replaceFragment(intent!!)
} else {
fragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as ConversationParentFragment fragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as ConversationParentFragment
} }
}
override fun onNewIntent(intent: Intent?) { override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent) super.onNewIntent(intent)
finish() setIntent(intent)
startActivity(intent) replaceFragment(intent!!)
}
private fun replaceFragment(intent: Intent) {
fragment = ConversationParentFragment.create(intent)
supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_container, fragment)
.disallowAddToBackStack()
.commitNowAllowingStateLoss()
} }
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean { override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {

View file

@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.conversation;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -35,6 +36,8 @@ public class ConversationIntents {
private static final String EXTRA_FIRST_TIME_IN_SELF_CREATED_GROUP = "first_time_in_group"; private static final String EXTRA_FIRST_TIME_IN_SELF_CREATED_GROUP = "first_time_in_group";
private static final String EXTRA_WITH_SEARCH_OPEN = "with_search_open"; private static final String EXTRA_WITH_SEARCH_OPEN = "with_search_open";
private static final String EXTRA_GIFT_BADGE = "gift_badge"; private static final String EXTRA_GIFT_BADGE = "gift_badge";
private static final String INTENT_DATA = "intent_data";
private static final String INTENT_TYPE = "intent_type";
private ConversationIntents() { private ConversationIntents() {
} }
@ -51,16 +54,35 @@ public class ConversationIntents {
return new Builder(context, BubbleConversationActivity.class, recipientId, threadId).build(); return new Builder(context, BubbleConversationActivity.class, recipientId, threadId).build();
} }
static boolean isInvalid(@NonNull Intent intent) { static boolean isInvalid(@NonNull Bundle arguments) {
if (isBubbleIntent(intent)) { Uri uri = getIntentData(arguments);
return intent.getData().getQueryParameter(EXTRA_RECIPIENT) == null; if (isBubbleIntentUri(uri)) {
return uri.getQueryParameter(EXTRA_RECIPIENT) == null;
} else { } else {
return !intent.hasExtra(EXTRA_RECIPIENT); return !arguments.containsKey(EXTRA_RECIPIENT);
} }
} }
private static boolean isBubbleIntent(@NonNull Intent intent) { static @Nullable Uri getIntentData(@NonNull Bundle bundle) {
return intent.getData() != null && Objects.equals(intent.getData().getAuthority(), BUBBLE_AUTHORITY); return bundle.getParcelable(INTENT_DATA);
}
static @Nullable String getIntentType(@NonNull Bundle bundle) {
return bundle.getString(INTENT_TYPE);
}
static @NonNull Bundle createParentFragmentArguments(@NonNull Intent intent) {
Bundle bundle = new Bundle();
bundle.putAll(intent.getExtras());
bundle.putParcelable(INTENT_DATA, intent.getData());
bundle.putString(INTENT_TYPE, intent.getType());
return bundle;
}
private static boolean isBubbleIntentUri(@Nullable Uri uri) {
return uri != null && Objects.equals(uri.getAuthority(), BUBBLE_AUTHORITY);
} }
final static class Args { final static class Args {
@ -76,10 +98,11 @@ public class ConversationIntents {
private final boolean withSearchOpen; private final boolean withSearchOpen;
private final Badge giftBadge; private final Badge giftBadge;
static Args from(@NonNull Intent intent) { static Args from(@NonNull Bundle arguments) {
if (isBubbleIntent(intent)) { Uri intentDataUri = getIntentData(arguments);
return new Args(RecipientId.from(intent.getData().getQueryParameter(EXTRA_RECIPIENT)), if (isBubbleIntentUri(intentDataUri)) {
Long.parseLong(intent.getData().getQueryParameter(EXTRA_THREAD_ID)), return new Args(RecipientId.from(intentDataUri.getQueryParameter(EXTRA_RECIPIENT)),
Long.parseLong(intentDataUri.getQueryParameter(EXTRA_THREAD_ID)),
null, null,
null, null,
null, null,
@ -91,17 +114,17 @@ public class ConversationIntents {
null); null);
} }
return new Args(RecipientId.from(Objects.requireNonNull(intent.getStringExtra(EXTRA_RECIPIENT))), return new Args(RecipientId.from(Objects.requireNonNull(arguments.getString(EXTRA_RECIPIENT))),
intent.getLongExtra(EXTRA_THREAD_ID, -1), arguments.getLong(EXTRA_THREAD_ID, -1),
intent.getStringExtra(EXTRA_TEXT), arguments.getString(EXTRA_TEXT),
intent.getParcelableArrayListExtra(EXTRA_MEDIA), arguments.getParcelableArrayList(EXTRA_MEDIA),
intent.getParcelableExtra(EXTRA_STICKER), arguments.getParcelable(EXTRA_STICKER),
intent.getBooleanExtra(EXTRA_BORDERLESS, false), arguments.getBoolean(EXTRA_BORDERLESS, false),
intent.getIntExtra(EXTRA_DISTRIBUTION_TYPE, ThreadDatabase.DistributionTypes.DEFAULT), arguments.getInt(EXTRA_DISTRIBUTION_TYPE, ThreadDatabase.DistributionTypes.DEFAULT),
intent.getIntExtra(EXTRA_STARTING_POSITION, -1), arguments.getInt(EXTRA_STARTING_POSITION, -1),
intent.getBooleanExtra(EXTRA_FIRST_TIME_IN_SELF_CREATED_GROUP, false), arguments.getBoolean(EXTRA_FIRST_TIME_IN_SELF_CREATED_GROUP, false),
intent.getBooleanExtra(EXTRA_WITH_SEARCH_OPEN, false), arguments.getBoolean(EXTRA_WITH_SEARCH_OPEN, false),
intent.getParcelableExtra(EXTRA_GIFT_BADGE)); arguments.getParcelable(EXTRA_GIFT_BADGE));
} }
private Args(@NonNull RecipientId recipientId, private Args(@NonNull RecipientId recipientId,

View file

@ -369,6 +369,8 @@ public class ConversationParentFragment extends Fragment
private static final String STATE_REACT_WITH_ANY_PAGE = "STATE_REACT_WITH_ANY_PAGE"; private static final String STATE_REACT_WITH_ANY_PAGE = "STATE_REACT_WITH_ANY_PAGE";
private static final String STATE_IS_SEARCH_REQUESTED = "STATE_IS_SEARCH_REQUESTED"; private static final String STATE_IS_SEARCH_REQUESTED = "STATE_IS_SEARCH_REQUESTED";
private static final String ARG_INTENT_DATA = "arg.intent.data";
private static final int REQUEST_CODE_SETTINGS = 1000; private static final int REQUEST_CODE_SETTINGS = 1000;
private static final int PICK_GALLERY = 1; private static final int PICK_GALLERY = 1;
@ -460,12 +462,20 @@ public class ConversationParentFragment extends Fragment
private final LifecycleDisposable disposables = new LifecycleDisposable(); private final LifecycleDisposable disposables = new LifecycleDisposable();
private final Debouncer optionsMenuDebouncer = new Debouncer(50); private final Debouncer optionsMenuDebouncer = new Debouncer(50);
private volatile boolean screenInitialized = false;
private IdentityRecordList identityRecords = new IdentityRecordList(Collections.emptyList()); private IdentityRecordList identityRecords = new IdentityRecordList(Collections.emptyList());
private Callback callback; private Callback callback;
private RecentEmojiPageModel recentEmojis; private RecentEmojiPageModel recentEmojis;
public static ConversationParentFragment create(Intent intent) {
ConversationParentFragment fragment = new ConversationParentFragment();
Bundle bundle = new Bundle();
bundle.putAll(ConversationIntents.createParentFragmentArguments(intent));
fragment.setArguments(bundle);
return fragment;
}
@Override @Override
public @NonNull View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public @NonNull View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.conversation_activity, container, false); return inflater.inflate(R.layout.conversation_activity, container, false);
@ -484,7 +494,7 @@ public class ConversationParentFragment extends Fragment
} }
// TODO [alex] LargeScreenSupport -- This check will no longer be valid / necessary // TODO [alex] LargeScreenSupport -- This check will no longer be valid / necessary
if (ConversationIntents.isInvalid(requireActivity().getIntent())) { if (ConversationIntents.isInvalid(requireArguments())) {
Log.w(TAG, "[onCreate] Missing recipientId!"); Log.w(TAG, "[onCreate] Missing recipientId!");
// TODO [greyson] Navigation // TODO [greyson] Navigation
startActivity(MainActivity.clearTop(requireContext())); startActivity(MainActivity.clearTop(requireContext()));
@ -499,8 +509,7 @@ public class ConversationParentFragment extends Fragment
// TODO [alex] LargeScreenSupport -- Should be removed once we move to multi-pane layout. // TODO [alex] LargeScreenSupport -- Should be removed once we move to multi-pane layout.
new FullscreenHelper(requireActivity()).showSystemUI(); new FullscreenHelper(requireActivity()).showSystemUI();
// TODO [alex] LargeScreenSupport -- This will need to be built from requireArguments() ConversationIntents.Args args = ConversationIntents.Args.from(requireArguments());
ConversationIntents.Args args = ConversationIntents.Args.from(requireActivity().getIntent());
if (savedInstanceState == null && args.getGiftBadge() != null) { if (savedInstanceState == null && args.getGiftBadge() != null) {
GiftThanksSheet.show(getChildFragmentManager(), args.getRecipientId(), args.getGiftBadge()); GiftThanksSheet.show(getChildFragmentManager(), args.getRecipientId(), args.getGiftBadge());
} }
@ -575,8 +584,6 @@ public class ConversationParentFragment extends Fragment
composeText.addTextChangedListener(typingTextWatcher); composeText.addTextChangedListener(typingTextWatcher);
} }
composeText.setSelection(composeText.length(), composeText.length()); composeText.setSelection(composeText.length(), composeText.length());
screenInitialized = true;
} }
}); });
} }
@ -600,78 +607,6 @@ public class ConversationParentFragment extends Fragment
sendButton.post(() -> sendButton.triggerSelectedChangedEvent()); sendButton.post(() -> sendButton.triggerSelectedChangedEvent());
} }
// TODO [alex] LargeScreenSupport -- This needs to be fed a stream of intents
protected void onNewIntent(Intent intent) {
Log.i(TAG, "onNewIntent()");
if (requireActivity().isFinishing()) {
Log.w(TAG, "Activity is finishing...");
return;
}
if (!screenInitialized) {
Log.w(TAG, "Activity is in the middle of initialization. Restarting.");
requireActivity().finish();
startActivity(intent);
return;
}
reactWithAnyEmojiStartPage = -1;
if (!Util.isEmpty(composeText) || attachmentManager.isAttachmentPresent() || inputPanel.hasSaveableContent()) {
saveDraft();
attachmentManager.clear(glideRequests, false);
inputPanel.clearQuote();
silentlySetComposeText("");
}
if (ConversationIntents.isInvalid(intent)) {
Log.w(TAG, "[onNewIntent] Missing recipientId!");
// TODO [greyson] Navigation
startActivity(MainActivity.clearTop(requireContext()));
requireActivity().finish();
return;
}
requireActivity().setIntent(intent);
ConversationIntents.Args args = ConversationIntents.Args.from(intent);
// TODO [alex] LargeScreenSupport - Set arguments
isSearchRequested = args.isWithSearchOpen();
viewModel.setArgs(args);
setVisibleThread(args.getThreadId());
reportShortcutLaunch(viewModel.getArgs().getRecipientId());
initializeResources(viewModel.getArgs());
initializeSecurity(recipient.get().isRegistered(), isDefaultSms).addListener(new AssertedSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean result) {
if (getContext() != null) {
Log.d(TAG, "Initializing draft from new intent...");
hasProcessedShareData = false;
initializeDraft(viewModel.getArgs());
}
}
});
if (fragment != null) {
fragment.onNewIntent();
}
searchNav.setVisibility(View.GONE);
if (args.isWithSearchOpen()) {
if (searchViewItem != null && searchViewItem.expandActionView()) {
searchViewModel.onSearchOpened();
}
} else {
searchViewModel.onSearchClosed();
viewModel.setSearchQuery(null);
inputPanel.setHideForSearch(false);
}
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
@ -1598,9 +1533,10 @@ public class ConversationParentFragment extends Fragment
private void handleManualMmsRequired() { private void handleManualMmsRequired() {
Toast.makeText(requireContext(), R.string.MmsDownloader_error_reading_mms_settings, Toast.LENGTH_LONG).show(); Toast.makeText(requireContext(), R.string.MmsDownloader_error_reading_mms_settings, Toast.LENGTH_LONG).show();
Bundle extras = requireActivity().getIntent().getExtras(); Bundle extras = requireArguments();
Intent intent = new Intent(requireContext(), PromptMmsActivity.class); Intent intent = new Intent(requireContext(), PromptMmsActivity.class);
if (extras != null) intent.putExtras(extras);
intent.putExtras(extras);
startActivity(intent); startActivity(intent);
} }
@ -1676,8 +1612,8 @@ public class ConversationParentFragment extends Fragment
} }
final CharSequence draftText = args.getDraftText(); final CharSequence draftText = args.getDraftText();
final Uri draftMedia = requireActivity().getIntent().getData(); final Uri draftMedia = ConversationIntents.getIntentData(requireArguments());
final String draftContentType = requireActivity().getIntent().getType(); final String draftContentType = ConversationIntents.getIntentType(requireArguments());
final MediaType draftMediaType = MediaType.from(draftContentType); final MediaType draftMediaType = MediaType.from(draftContentType);
final List<Media> mediaList = args.getMedia(); final List<Media> mediaList = args.getMedia();
final StickerLocator stickerLocator = args.getStickerLocator(); final StickerLocator stickerLocator = args.getStickerLocator();

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android" <androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container" android:id="@+id/fragment_container"
android:name="org.thoughtcrime.securesms.conversation.ConversationParentFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />