Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 50 additions & 20 deletions packages/react-native/React/CoreModules/RCTDeviceInfo.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -31,23 +29,40 @@ @implementation RCTDeviceInfo {
NSDictionary *_currentInterfaceDimensions;
BOOL _isFullscreen;
std::atomic<BOOL> _invalidated;
NSDictionary *_constants;

__weak UIWindow *_applicationWindow;
}

static NSString *const kFrameKeyPath = @"frame";

@synthesize moduleRegistry = _moduleRegistry;

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
Expand Down Expand Up @@ -81,7 +96,7 @@ - (void)initialize

#if TARGET_OS_IOS

_currentInterfaceOrientation = [RCTKeyWindowValuesProxy sharedInstance].currentInterfaceOrientation;
_currentInterfaceOrientation = RCTKeyWindow().windowScene.interfaceOrientation;

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(interfaceFrameDidChange)
Expand All @@ -98,6 +113,15 @@ - (void)initialize
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
Expand All @@ -120,6 +144,8 @@ - (void)_cleanupObservers

[[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
Expand All @@ -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

Expand All @@ -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),
Expand All @@ -170,7 +203,10 @@ - (NSDictionary *)_exportedDimensions
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);
}
Expand All @@ -182,14 +218,7 @@ - (NSDictionary *)_exportedDimensions

- (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
Expand All @@ -209,10 +238,11 @@ - (void)didReceiveNewContentSizeMultiplier
- (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->
Expand Down Expand Up @@ -275,4 +305,4 @@ - (void)_interfaceFrameDidChange
Class RCTDeviceInfoCls(void)
{
return RCTDeviceInfo.class;
}
}
Loading