Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -33,62 +33,6 @@
NSNotificationName const FlutterViewControllerShowHomeIndicator =
@"FlutterViewControllerShowHomeIndicator";

/// Class to coalesce calls for a period of time.
///
/// This is used to filter out the conflicting notifications that can get sent
/// in rapid succession when the app gets foregrounded.
@interface FlutterCoalescer : NSObject
@property(nonatomic, assign) BOOL isTriggered;
@property(nonatomic, assign) BOOL isCoalescing;
@property(nonatomic, copy) dispatch_block_t block;
@end

@implementation FlutterCoalescer
- (instancetype)initWithBlock:(dispatch_block_t)block {
self = [super init];
if (self) {
self.block = block;
}
return self;
}

- (void)dealloc {
[_block release];
[super dealloc];
}

- (void)trigger {
if (_isCoalescing) {
_isTriggered = YES;
} else {
_isTriggered = NO;
if (_block) {
_block();
}
}
}

- (void)coalesceForSeconds:(double)seconds {
if (self.isCoalescing || !self.block) {
return;
}
self.isCoalescing = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC),
dispatch_get_main_queue(), ^{
if (self.isTriggered && self.block) {
self.block();
}
self.isTriggered = NO;
self.isCoalescing = NO;
});
}

- (void)invalidate {
self.block = nil;
}

@end // FlutterCoalescer

// This is left a FlutterBinaryMessenger privately for now to give people a chance to notice the
// change. Unfortunately unless you have Werror turned on, incompatible pointers as arguments are
// just a warning.
Expand Down Expand Up @@ -127,9 +71,6 @@ @implementation FlutterViewController {
BOOL _viewOpaque;
BOOL _engineNeedsLaunch;
NSMutableSet<NSNumber*>* _ongoingTouches;
// Coalescer that filters out superfluous keyboard notifications when the app
// is being foregrounded.
fml::scoped_nsobject<FlutterCoalescer> _updateViewportMetrics;
// This scroll view is a workaround to accomodate iOS 13 and higher. There isn't a way to get
// touches on the status bar to trigger scrolling to the top of a scroll view. We place a
// UIScrollView with height zero and a content offset so we can get those events. See also:
Expand Down Expand Up @@ -226,11 +167,6 @@ - (void)performCommonViewControllerInitialization {
_statusBarStyle = UIStatusBarStyleDefault;

[self setupNotificationCenterObservers];

__block FlutterViewController* blockSelf = self;
_updateViewportMetrics.reset([[FlutterCoalescer alloc] initWithBlock:^{
[blockSelf updateViewportMetricsImplementation];
}]);
}

- (FlutterEngine*)engine {
Expand Down Expand Up @@ -668,7 +604,6 @@ - (void)dealloc {
userInfo:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_ongoingTouches release];
[_updateViewportMetrics invalidate];
[super dealloc];
}

Expand All @@ -695,7 +630,6 @@ - (void)applicationDidEnterBackground:(NSNotification*)notification {
- (void)applicationWillEnterForeground:(NSNotification*)notification {
TRACE_EVENT0("flutter", "applicationWillEnterForeground");
[self goToApplicationLifecycle:@"AppLifecycleState.inactive"];
[_updateViewportMetrics coalesceForSeconds:0.5];
}

// Make this transition only while this current view controller is visible.
Expand Down Expand Up @@ -886,13 +820,6 @@ - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
#pragma mark - Handle view resizing

- (void)updateViewportMetrics {
[_updateViewportMetrics trigger];
}

/// The direct implementation of updateViewportMetrics, it doesn't conform to
/// the coalescing logic when foregrounding the app. Most calls should be
/// directed to [updateViewportMetrics].
- (void)updateViewportMetricsImplementation {
[_engine.get() updateViewportMetrics:_viewportMetrics];
}

Expand Down Expand Up @@ -920,7 +847,7 @@ - (void)viewDidLayoutSubviews {
_viewportMetrics.physical_height = viewSize.height * scale;

[self updateViewportPadding];
[self updateViewportMetricsImplementation];
[self updateViewportMetrics];

// This must run after updateViewportMetrics so that the surface creation tasks are queued after
// the viewport metrics update tasks.
Expand Down Expand Up @@ -967,6 +894,14 @@ - (void)updateViewportPadding {

- (void)keyboardWillChangeFrame:(NSNotification*)notification {
NSDictionary* info = [notification userInfo];

if (@available(iOS 9, *)) {
// Ignore keyboard notifications related to other apps.
if (![info[UIKeyboardIsLocalUserInfoKey] boolValue]) {
Copy link
Member

@chinmaygarde chinmaygarde Apr 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find guidance in the documentation on whether this key will always be present. The discussion in the docs seems to be around multitasking on iPad. As it stands, if the key is not present in the dictionary, the frame change will be ignored. A more defensive writing of this piece of code would be to check if the key exists and then check its bool value. If the key doesn't exist, process the frame change as normal.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. In practice it isn't just iPad, these were the very notifications that were messing us up and I was testing with iPhone. I believe the key is always present (except iOS 8). It doesn't hurt to make it safer.

return;
}
}

CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect screenRect = [[UIScreen mainScreen] bounds];

Expand Down