# This patch fixes two issues:
# - Updates RCTDeviceInfo.m to match https://github.com/facebook/react-native/commit/0b8db7e5e814cfbf9974cc5b6ceb64e8006d8a3c.
#   This fixes an issue in which useWindowDimensions returns incorrect
#   values in landscape mode in iOS.
#   This should be fixed in React Native 0.80. See https://github.com/facebook/react-native/issues/51086.
# - Updates NativeAnimatedModule.java to work around an Android 12-specific crash.
diff --git a/React/CoreModules/RCTDeviceInfo.mm b/React/CoreModules/RCTDeviceInfo.mm
index 6b4fcef852252e8d4ac2aceb12175fdfafb4def7..8ceab21e8653d429876d10e2d12ed1342780ad7d 100644
--- a/React/CoreModules/RCTDeviceInfo.mm
+++ b/React/CoreModules/RCTDeviceInfo.mm
@@ -14,9 +14,7 @@
 #import <React/RCTEventDispatcherProtocol.h>
 #import <React/RCTInitializing.h>
 #import <React/RCTInvalidating.h>
-#import <React/RCTKeyWindowValuesProxy.h>
 #import <React/RCTUtils.h>
-#import <React/RCTWindowSafeAreaProxy.h>
 #import <atomic>
 
 #import "CoreModulesPlugins.h"
@@ -31,8 +29,13 @@ using namespace facebook::react;
   NSDictionary *_currentInterfaceDimensions;
   BOOL _isFullscreen;
   std::atomic<BOOL> _invalidated;
+  NSDictionary *_constants;
+
+  __weak UIWindow *_applicationWindow;
 }
 
+static NSString *const kFrameKeyPath = @"frame";
+
 @synthesize moduleRegistry = _moduleRegistry;
 
 RCT_EXPORT_MODULE()
@@ -40,14 +43,26 @@ RCT_EXPORT_MODULE()
 - (instancetype)init
 {
   if (self = [super init]) {
-    [[RCTKeyWindowValuesProxy sharedInstance] startObservingWindowSizeIfNecessary];
+    _applicationWindow = RCTKeyWindow();
+    [_applicationWindow addObserver:self forKeyPath:kFrameKeyPath options:NSKeyValueObservingOptionNew context:nil];
   }
   return self;
 }
 
+- (void)observeValueForKeyPath:(NSString *)keyPath
+                      ofObject:(id)object
+                        change:(NSDictionary *)change
+                       context:(void *)context
+{
+  if ([keyPath isEqualToString:kFrameKeyPath]) {
+    [self interfaceFrameDidChange];
+    [[NSNotificationCenter defaultCenter] postNotificationName:RCTWindowFrameDidChangeNotification object:self];
+  }
+}
+
 + (BOOL)requiresMainQueueSetup
 {
-  return NO;
+  return YES;
 }
 
 - (dispatch_queue_t)methodQueue
@@ -81,7 +96,7 @@ RCT_EXPORT_MODULE()
 
 #if TARGET_OS_IOS
 
-  _currentInterfaceOrientation = [RCTKeyWindowValuesProxy sharedInstance].currentInterfaceOrientation;
+  _currentInterfaceOrientation = RCTKeyWindow().windowScene.interfaceOrientation;
 
   [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(interfaceFrameDidChange)
@@ -98,6 +113,15 @@ RCT_EXPORT_MODULE()
                                            selector:@selector(invalidate)
                                                name:RCTBridgeWillInvalidateModulesNotification
                                              object:nil];
+
+  _constants = @{
+    @"Dimensions" : [self _exportedDimensions],
+    // Note:
+    // This prop is deprecated and will be removed in a future release.
+    // Please use this only for a quick and temporary solution.
+    // Use <SafeAreaView> instead.
+    @"isIPhoneX_deprecated" : @(RCTIsIPhoneNotched()),
+  };
 }
 
 - (void)invalidate
@@ -120,6 +144,8 @@ RCT_EXPORT_MODULE()
 
   [[NSNotificationCenter defaultCenter] removeObserver:self name:RCTBridgeWillInvalidateModulesNotification object:nil];
 
+  [_applicationWindow removeObserver:self forKeyPath:kFrameKeyPath];
+
 #if TARGET_OS_IOS
   [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
 #endif
@@ -132,8 +158,13 @@ static BOOL RCTIsIPhoneNotched()
 
 #if TARGET_OS_IOS
   dispatch_once(&onceToken, ^{
+    RCTAssertMainQueue();
+
     // 20pt is the top safeArea value in non-notched devices
-    isIPhoneNotched = [RCTWindowSafeAreaProxy sharedInstance].currentSafeAreaInsets.top > 20;
+    UIWindow *keyWindow = RCTKeyWindow();
+    if (keyWindow) {
+      isIPhoneNotched = keyWindow.safeAreaInsets.top > 20;
+    }
   });
 #endif
 
@@ -142,11 +173,13 @@ static BOOL RCTIsIPhoneNotched()
 
 static NSDictionary *RCTExportedDimensions(CGFloat fontScale)
 {
+  RCTAssertMainQueue();
   UIScreen *mainScreen = UIScreen.mainScreen;
   CGSize screenSize = mainScreen.bounds.size;
+  UIView *mainWindow = RCTKeyWindow();
 
   // We fallback to screen size if a key window is not found.
-  CGSize windowSize = [RCTKeyWindowValuesProxy sharedInstance].windowSize;
+  CGSize windowSize = mainWindow ? mainWindow.bounds.size : screenSize;
 
   NSDictionary<NSString *, NSNumber *> *dimsWindow = @{
     @"width" : @(windowSize.width),
@@ -170,7 +203,10 @@ static NSDictionary *RCTExportedDimensions(CGFloat fontScale)
   RCTAssert(_moduleRegistry, @"Failed to get exported dimensions: RCTModuleRegistry is nil");
   RCTAccessibilityManager *accessibilityManager =
       (RCTAccessibilityManager *)[_moduleRegistry moduleForName:"AccessibilityManager"];
-  RCTAssert(accessibilityManager, @"Failed to get exported dimensions: AccessibilityManager is nil");
+  // TOOD(T225745315): For some reason, accessibilityManager is nil in some cases.
+  // We default the fontScale to 1.0 in this case. This should be okay: if we assume
+  // that accessibilityManager will eventually become available, js will eventually
+  // be updated with the correct fontScale.
   CGFloat fontScale = accessibilityManager ? accessibilityManager.multiplier : 1.0;
   return RCTExportedDimensions(fontScale);
 }
@@ -182,14 +218,7 @@ static NSDictionary *RCTExportedDimensions(CGFloat fontScale)
 
 - (NSDictionary<NSString *, id> *)getConstants
 {
-  return @{
-    @"Dimensions" : [self _exportedDimensions],
-    // Note:
-    // This prop is deprecated and will be removed in a future release.
-    // Please use this only for a quick and temporary solution.
-    // Use <SafeAreaView> instead.
-    @"isIPhoneX_deprecated" : @(RCTIsIPhoneNotched()),
-  };
+  return _constants;
 }
 
 - (void)didReceiveNewContentSizeMultiplier
@@ -209,10 +238,11 @@ static NSDictionary *RCTExportedDimensions(CGFloat fontScale)
 - (void)interfaceOrientationDidChange
 {
 #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
-  UIWindow *keyWindow = RCTKeyWindow();
-  UIInterfaceOrientation nextOrientation = keyWindow.windowScene.interfaceOrientation;
+  UIApplication *application = RCTSharedApplication();
+  UIInterfaceOrientation nextOrientation = RCTKeyWindow().windowScene.interfaceOrientation;
 
-  BOOL isRunningInFullScreen = CGRectEqualToRect(keyWindow.frame, keyWindow.screen.bounds);
+  BOOL isRunningInFullScreen =
+      CGRectEqualToRect(application.delegate.window.frame, application.delegate.window.screen.bounds);
   // We are catching here two situations for multitasking view:
   // a) The app is in Split View and the container gets resized -> !isRunningInFullScreen
   // b) The app changes to/from fullscreen example: App runs in slide over mode and goes into fullscreen->
@@ -276,3 +306,4 @@ Class RCTDeviceInfoCls(void)
 {
   return RCTDeviceInfo.class;
 }
+
diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
index cf14e51cf5f561b84f1b6ace8410fc77d626758e..abc8c64adf26fbf73429aee7fd4f76877e98849a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
@@ -42,6 +42,7 @@ import java.util.List;
 import java.util.Queue;
 import java.util.Set;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.LinkedBlockingQueue; 
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -155,8 +156,15 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
   }
 
   private class ConcurrentOperationQueue {
-    private final Queue<UIThreadOperation> mQueue = new ConcurrentLinkedQueue<>();
-    @Nullable private UIThreadOperation mPeekedOperation = null;
+    // Patch: Use LinkedBlockingQueue instead of ConcurrentLinkedQueue.
+    // In some versions of Android, ConcurrentLinkedQueue is known to drop
+    // items, causing crashing. See https://github.com/laurent22/joplin/issues/8425
+    private final Queue<UIThreadOperation> mQueue = (
+		// The issue exists for Android 12, which corresponds to API levels 31 and 32.
+		Build.VERSION.SDK_INT == 31 || Build.VERSION.SDK_INT == 32
+	) ? new LinkedBlockingQueue<>() : new ConcurrentLinkedQueue<>();
+
+	@Nullable private UIThreadOperation mPeekedOperation = null;
 
     @AnyThread
     boolean isEmpty() {
