From 067a22ff9093a9e26bc6dc86f9ed936805d4f866 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Wed, 10 Dec 2025 09:34:53 -0400 Subject: [PATCH] Fix crash when keyboard animation ends after view destroyed. --- .../components/InputAwareConstraintLayout.kt | 6 +++--- .../conversation/v2/ConversationFragment.kt | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/InputAwareConstraintLayout.kt b/app/src/main/java/org/thoughtcrime/securesms/components/InputAwareConstraintLayout.kt index c5757ee3f9..4453f8ba82 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/InputAwareConstraintLayout.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/InputAwareConstraintLayout.kt @@ -37,7 +37,7 @@ class InputAwareConstraintLayout @JvmOverloads constructor( listeners.add(listener) } - fun remoteInputListener(listener: Listener) { + fun removeInputListener(listener: Listener) { listeners.remove(listener) } @@ -57,13 +57,13 @@ class InputAwareConstraintLayout @JvmOverloads constructor( val listener = object : Listener, KeyboardStateListener { override fun onInputHidden() { onHidden() - remoteInputListener(this) + removeInputListener(this) removeKeyboardStateListener(this) } override fun onKeyboardHidden() { onHidden() - remoteInputListener(this) + removeInputListener(this) removeKeyboardStateListener(this) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt index 3b8d894a40..fc93b0a9c6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt @@ -569,6 +569,7 @@ class ConversationFragment : private var dataObserver: DataObserver? = null private var menuProvider: ConversationOptionsMenu.Provider? = null private var scrollListener: ScrollListener? = null + private var keyboardEvents: KeyboardEvents? = null private var progressDialog: ProgressCardDialogFragment? = null private val jumpAndPulseScrollStrategy = object : ScrollToPositionDelegate.ScrollStrategy { @@ -770,6 +771,12 @@ class ConversationFragment : } override fun onDestroyView() { + keyboardEvents?.let { + container.removeInputListener(it) + container.removeKeyboardStateListener(it) + } + keyboardEvents = null + super.onDestroyView() if (pinnedShortcutReceiver != null) { requireActivity().unregisterReceiver(pinnedShortcutReceiver) @@ -1154,9 +1161,10 @@ class ConversationFragment : dataObserver = DataObserver() adapter.registerAdapterDataObserver(dataObserver!!) - val keyboardEvents = KeyboardEvents() - container.addInputListener(keyboardEvents) - container.addKeyboardStateListener(keyboardEvents) + keyboardEvents = KeyboardEvents().also { + container.addInputListener(it) + container.addKeyboardStateListener(it) + } childFragmentManager.setFragmentResultListener(AttachmentKeyboardFragment.RESULT_KEY, viewLifecycleOwner, AttachmentKeyboardFragmentListener()) motionEventRelay.setDrain(MotionEventRelayDrain(this)) @@ -4745,6 +4753,9 @@ class ConversationFragment : } override fun onKeyboardAnimationEnded() { + if (view == null) { + return + } if (!container.isKeyboardShowing) { closeEmojiSearch() }