33import android .os .Bundle ;
44import android .view .View ;
55import android .view .ViewGroup ;
6+ import android .view .ViewTreeObserver ;
67import androidx .annotation .NonNull ;
78import androidx .fragment .app .Fragment ;
89import androidx .fragment .app .FragmentManager ;
1314import com .facebook .react .uimanager .events .EventDispatcher ;
1415import com .facebook .react .uimanager .events .EventDispatcherListener ;
1516import io .sentry .ILogger ;
17+ import io .sentry .Integration ;
18+ import io .sentry .ScopesAdapter ;
1619import io .sentry .SentryLevel ;
20+ import io .sentry .SentryOptions ;
1721import io .sentry .android .core .BuildInfoProvider ;
1822import io .sentry .android .core .internal .util .FirstDrawDoneListener ;
23+ import io .sentry .android .replay .ReplayIntegration ;
1924import org .jetbrains .annotations .NotNull ;
2025import org .jetbrains .annotations .Nullable ;
2126
@@ -25,6 +30,10 @@ public class RNSentryReactFragmentLifecycleTracer extends FragmentLifecycleCallb
2530 private @ NotNull final Runnable emitNewFrameEvent ;
2631 private @ NotNull final ILogger logger ;
2732
33+ private @ Nullable ReplayIntegration replayIntegration ;
34+ private int lastWidth = -1 ;
35+ private int lastHeight = -1 ;
36+
2837 public RNSentryReactFragmentLifecycleTracer (
2938 @ NotNull BuildInfoProvider buildInfoProvider ,
3039 @ NotNull Runnable emitNewFrameEvent ,
@@ -95,6 +104,75 @@ public void onEventDispatch(Event event) {
95104 }
96105 }
97106 });
107+
108+ // Add layout listener to detect configuration changes
109+ attachLayoutChangeListener (v );
110+ }
111+
112+ private void attachLayoutChangeListener (final View view ) {
113+ view .getViewTreeObserver ()
114+ .addOnGlobalLayoutListener (
115+ new ViewTreeObserver .OnGlobalLayoutListener () {
116+ @ Override
117+ public void onGlobalLayout () {
118+ checkAndNotifyWindowSizeChange (view );
119+ }
120+ });
121+ }
122+
123+ private void checkAndNotifyWindowSizeChange (View view ) {
124+ try {
125+ android .util .DisplayMetrics metrics = view .getContext ().getResources ().getDisplayMetrics ();
126+ int currentWidth = metrics .widthPixels ;
127+ int currentHeight = metrics .heightPixels ;
128+
129+ if (lastWidth != currentWidth || lastHeight != currentHeight ) {
130+ lastWidth = currentWidth ;
131+ lastHeight = currentHeight ;
132+
133+ notifyReplayIntegrationOfSizeChange (currentWidth , currentHeight );
134+ }
135+ } catch (Exception e ) {
136+ logger .log (SentryLevel .DEBUG , "Failed to check window size" , e );
137+ }
138+ }
139+
140+ private void notifyReplayIntegrationOfSizeChange (int width , int height ) {
141+ try {
142+ if (replayIntegration == null ) {
143+ replayIntegration = getReplayIntegration ();
144+ }
145+
146+ if (replayIntegration == null ) {
147+ return ;
148+ }
149+
150+ if (!replayIntegration .isRecording ()) {
151+ return ;
152+ }
153+
154+ replayIntegration .onWindowSizeChanged (width , height );
155+ } catch (Exception e ) {
156+ logger .log (SentryLevel .DEBUG , "Failed to notify replay integration of size change" , e );
157+ }
158+ }
159+
160+ private @ Nullable ReplayIntegration getReplayIntegration () {
161+ try {
162+ final SentryOptions options = ScopesAdapter .getInstance ().getOptions ();
163+ if (options == null ) {
164+ return null ;
165+ }
166+
167+ for (Integration integration : options .getIntegrations ()) {
168+ if (integration instanceof ReplayIntegration ) {
169+ return (ReplayIntegration ) integration ;
170+ }
171+ }
172+ } catch (Exception e ) {
173+ logger .log (SentryLevel .DEBUG , "Error getting replay integration" , e );
174+ }
175+ return null ;
98176 }
99177
100178 private static @ Nullable EventDispatcher getEventDispatcherForReactTag (
0 commit comments