Skip to content

Fix back gesture unresponsive state and fragment stack corruption#1936

Open
rybnikov wants to merge 1 commit intoDrKLO:masterfrom
rybnikov:fix/back-gesture-and-fragment-stack
Open

Fix back gesture unresponsive state and fragment stack corruption#1936
rybnikov wants to merge 1 commit intoDrKLO:masterfrom
rybnikov:fix/back-gesture-and-fragment-stack

Conversation

@rybnikov
Copy link
Copy Markdown

@rybnikov rybnikov commented Feb 23, 2026

Summary

Fixes two independent issues that cause navigation to break, particularly on foldable devices and when sharing content from external apps.

1. Animation state stuck across activity lifecycle

Navigation in ActionBarLayout is gated by several boolean flags: transitionAnimationInProgress, animationInProgress, predictiveInput, predictiveBackInProgress, and startedTracking. When any of these are true, onBackPressed(), presentFragment(), and touch events are blocked.

These flags can get stuck when the activity goes through onPause()/onResume() while an animation is in progress (e.g., user switches apps mid-gesture, foldable device triggers configuration change during transition). The original code had a commented-out attempt to handle this in onResume() — it called onCloseAnimationEnd()/onOpenAnimationEnd(), but those execute callbacks that modify the fragment stack (closeLastFragmentInternalRemoveOld), which is unsafe during lifecycle events.

Fix: Added forceResetAnimationState() that resets all animation flags and discards pending callbacks instead of executing them. Called from both onResume() and onPause().

2. Stale activity instance destroys shared state

LaunchActivity uses static collections (mainFragmentsStack, layerFragmentsStack, rightFragmentsStack) shared across all instances. Multiple instances can coexist when:

  • Sharing content from external apps creates a new activity in a separate task
  • Activity is recreated after finish() (common with back gesture on foldables)
  • Configuration changes on foldable devices

When onDestroy() runs on a stale instance, it unconditionally:

  • Calls clearFragments(), emptying the static fragment stacks used by the active instance
  • Destroys global singletons (PhotoViewer, Theme, MediaController, etc.) that the active instance relies on

This leaves the active instance with empty navigation stacks and destroyed UI components — back button silently does nothing, screens can't be opened, viewers are broken.

Fix: Guard both clearFragments() and global singleton teardown with instance == this, so only the currently active instance performs cleanup. Also fixed SDK 33 back callback unregistration checking the wrong variable (onBackAnimationCallback instead of onBackInvokedCallback).

Files changed

  • ActionBarLayout.java — add forceResetAnimationState(), call from onResume()/onPause()
  • LaunchActivity.java — guard clearFragments() and global UI teardown in onDestroy() with instance == this; fix SDK 33 callback variable

Test plan

  • Open chat, use back gesture — returns to dialog list (not stuck)
  • Rapidly switch between chats and back — no unresponsive state
  • Fold/unfold device during navigation animation — app remains responsive
  • Share content to Telegram from external app, navigate back — fragments intact
  • Kill and reopen app after navigating into a chat — fragment stack preserved
  • Open PhotoViewer, switch apps, return — PhotoViewer still functional

Two independent issues that cause navigation to break:

1. Animation state flags (transitionAnimationInProgress, animationInProgress,
   predictiveInput, etc.) can persist across activity lifecycle events,
   permanently blocking back presses, touch events, and fragment navigation.
   Added forceResetAnimationState() called from onResume()/onPause() to
   clear stale animation state. Callbacks are discarded rather than executed
   to avoid modifying the fragment stack during lifecycle transitions.

2. LaunchActivity.onDestroy() unconditionally calls clearFragments() and
   destroys global singletons (PhotoViewer, Theme, MediaController, etc.).
   When a new activity instance exists (share intents, foldable config
   changes, activity recreation after finish()), the stale instance's
   onDestroy tears down UI and fragments used by the active instance.
   Guarded both clearFragments() and global singleton teardown with
   instance == this check. Also fixed SDK 33 back callback unregistration
   checking wrong variable (onBackAnimationCallback vs onBackInvokedCallback).
@rybnikov rybnikov force-pushed the fix/back-gesture-and-fragment-stack branch from 1e637cd to ba264be Compare February 27, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants