From 251f7428cbc043031db05fbfe542bfeff9b9f9d1 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 30 Jan 2020 14:59:13 -0800 Subject: [PATCH 1/7] Started coallescing updates to viewport metrics after foregrounding the app. --- .../framework/Source/FlutterViewController.mm | 62 ++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 1e082ec4ebd97..b7dcb224850e8 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -27,6 +27,53 @@ NSNotificationName const FlutterViewControllerWillDealloc = @"FlutterViewControllerWillDealloc"; +/// Class to coallesce calls for a period of time. +@interface FlutterCoallescer : NSObject +@property (nonatomic, assign) BOOL isTriggered; +@property (nonatomic, assign) BOOL isCoallescing; +@property (nonatomic, copy) dispatch_block_t block; +@end + +@implementation FlutterCoallescer +-(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 (_isCoallescing) { + _isTriggered = YES; + } else { + _isTriggered = NO; + _block(); + } +} + +-(void)coallesceForSeconds:(double)seconds { + if (self.isCoallescing) { + return; + } + NSLog(@"aaclarke start coallescing"); + self.isCoallescing = YES; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + if (self.isTriggered) { + self.block(); + } + self.isTriggered = NO; + self.isCoallescing = NO; + NSLog(@"aaclarke stop coallescing"); + }); +} +@end // FlutterCoallescer + // 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. @@ -64,6 +111,7 @@ @implementation FlutterViewController { BOOL _viewOpaque; BOOL _engineNeedsLaunch; NSMutableSet* _ongoingTouches; + fml::scoped_nsobject _updateViewportMetrics; } @synthesize displayingFlutterUI = _displayingFlutterUI; @@ -147,6 +195,11 @@ - (void)performCommonViewControllerInitialization { _statusBarStyle = UIStatusBarStyleDefault; [self setupNotificationCenterObservers]; + + __block FlutterViewController* blockSelf = self; + _updateViewportMetrics.reset([[FlutterCoallescer alloc] initWithBlock:^{ + [blockSelf updateViewportMetricsImplementation]; + }]); } - (FlutterEngine*)engine { @@ -557,6 +610,7 @@ - (void)applicationDidEnterBackground:(NSNotification*)notification { - (void)applicationWillEnterForeground:(NSNotification*)notification { TRACE_EVENT0("flutter", "applicationWillEnterForeground"); [self goToApplicationLifecycle:@"AppLifecycleState.inactive"]; + [_updateViewportMetrics coallesceForSeconds:0.5]; } // Make this transition only while this current view controller is visible. @@ -741,6 +795,10 @@ - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { #pragma mark - Handle view resizing - (void)updateViewportMetrics { + [_updateViewportMetrics trigger]; +} + +- (void)updateViewportMetricsImplementation { [_engine.get() updateViewportMetrics:_viewportMetrics]; } @@ -764,7 +822,7 @@ - (void)viewDidLayoutSubviews { _viewportMetrics.physical_height = viewSize.height * scale; [self updateViewportPadding]; - [self updateViewportMetrics]; + [self updateViewportMetricsImplementation]; // This must run after updateViewportMetrics so that the surface creation tasks are queued after // the viewport metrics update tasks. @@ -818,11 +876,13 @@ - (void)keyboardWillChangeFrame:(NSNotification*)notification { // keyboard height. The Dart side will compute a value accounting for the keyboard-consuming // bottom padding. _viewportMetrics.physical_view_inset_bottom = bottom * scale; + NSLog(@"bottom inset:%f", _viewportMetrics.physical_view_inset_bottom); [self updateViewportMetrics]; } - (void)keyboardWillBeHidden:(NSNotification*)notification { _viewportMetrics.physical_view_inset_bottom = 0; + NSLog(@"bottom inset:%f", _viewportMetrics.physical_view_inset_bottom); [self updateViewportMetrics]; } From f7a9e111076bb80a17ddf2a126ac2ec8dda24f01 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 30 Jan 2020 15:40:47 -0800 Subject: [PATCH 2/7] Cleaned up the code a bit. --- .../framework/Source/FlutterViewController.mm | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index b7dcb224850e8..3a826d35b0b62 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -27,14 +27,14 @@ NSNotificationName const FlutterViewControllerWillDealloc = @"FlutterViewControllerWillDealloc"; -/// Class to coallesce calls for a period of time. -@interface FlutterCoallescer : NSObject +/// Class to coalesce calls for a period of time. +@interface FlutterCoalescer : NSObject @property (nonatomic, assign) BOOL isTriggered; @property (nonatomic, assign) BOOL isCoallescing; @property (nonatomic, copy) dispatch_block_t block; @end -@implementation FlutterCoallescer +@implementation FlutterCoalescer -(instancetype)initWithBlock:(dispatch_block_t)block { self = [super init]; if (self) { @@ -57,7 +57,7 @@ -(void)trigger { } } --(void)coallesceForSeconds:(double)seconds { +-(void)coalesceForSeconds:(double)seconds { if (self.isCoallescing) { return; } @@ -72,7 +72,7 @@ -(void)coallesceForSeconds:(double)seconds { NSLog(@"aaclarke stop coallescing"); }); } -@end // FlutterCoallescer +@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 @@ -111,7 +111,9 @@ @implementation FlutterViewController { BOOL _viewOpaque; BOOL _engineNeedsLaunch; NSMutableSet* _ongoingTouches; - fml::scoped_nsobject _updateViewportMetrics; + // Coalescer that filters out superfluous keyboard notifications when the app + // is being foregrounded. + fml::scoped_nsobject _updateViewportMetrics; } @synthesize displayingFlutterUI = _displayingFlutterUI; @@ -197,7 +199,7 @@ - (void)performCommonViewControllerInitialization { [self setupNotificationCenterObservers]; __block FlutterViewController* blockSelf = self; - _updateViewportMetrics.reset([[FlutterCoallescer alloc] initWithBlock:^{ + _updateViewportMetrics.reset([[FlutterCoalescer alloc] initWithBlock:^{ [blockSelf updateViewportMetricsImplementation]; }]); } @@ -610,7 +612,7 @@ - (void)applicationDidEnterBackground:(NSNotification*)notification { - (void)applicationWillEnterForeground:(NSNotification*)notification { TRACE_EVENT0("flutter", "applicationWillEnterForeground"); [self goToApplicationLifecycle:@"AppLifecycleState.inactive"]; - [_updateViewportMetrics coallesceForSeconds:0.5]; + [_updateViewportMetrics coalesceForSeconds:0.5]; } // Make this transition only while this current view controller is visible. @@ -798,6 +800,9 @@ - (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]; } From 68017424c532407a76f6695f7d8f68c7efd3c684 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 30 Jan 2020 15:41:54 -0800 Subject: [PATCH 3/7] removed print statements --- .../darwin/ios/framework/Source/FlutterViewController.mm | 4 ---- 1 file changed, 4 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 3a826d35b0b62..d1e94a94e299b 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -61,7 +61,6 @@ -(void)coalesceForSeconds:(double)seconds { if (self.isCoallescing) { return; } - NSLog(@"aaclarke start coallescing"); self.isCoallescing = YES; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ if (self.isTriggered) { @@ -69,7 +68,6 @@ -(void)coalesceForSeconds:(double)seconds { } self.isTriggered = NO; self.isCoallescing = NO; - NSLog(@"aaclarke stop coallescing"); }); } @end // FlutterCoalescer @@ -881,13 +879,11 @@ - (void)keyboardWillChangeFrame:(NSNotification*)notification { // keyboard height. The Dart side will compute a value accounting for the keyboard-consuming // bottom padding. _viewportMetrics.physical_view_inset_bottom = bottom * scale; - NSLog(@"bottom inset:%f", _viewportMetrics.physical_view_inset_bottom); [self updateViewportMetrics]; } - (void)keyboardWillBeHidden:(NSNotification*)notification { _viewportMetrics.physical_view_inset_bottom = 0; - NSLog(@"bottom inset:%f", _viewportMetrics.physical_view_inset_bottom); [self updateViewportMetrics]; } From 1a391fc4d410c11fc1740dbea5ed0fde4ccc91e1 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 30 Jan 2020 15:43:15 -0800 Subject: [PATCH 4/7] ran formatter --- .../framework/Source/FlutterViewController.mm | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index d1e94a94e299b..d89319f874880 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -29,13 +29,13 @@ /// Class to coalesce calls for a period of time. @interface FlutterCoalescer : NSObject -@property (nonatomic, assign) BOOL isTriggered; -@property (nonatomic, assign) BOOL isCoallescing; -@property (nonatomic, copy) dispatch_block_t block; +@property(nonatomic, assign) BOOL isTriggered; +@property(nonatomic, assign) BOOL isCoallescing; +@property(nonatomic, copy) dispatch_block_t block; @end @implementation FlutterCoalescer --(instancetype)initWithBlock:(dispatch_block_t)block { +- (instancetype)initWithBlock:(dispatch_block_t)block { self = [super init]; if (self) { self.block = block; @@ -48,7 +48,7 @@ - (void)dealloc { [super dealloc]; } --(void)trigger { +- (void)trigger { if (_isCoallescing) { _isTriggered = YES; } else { @@ -57,20 +57,21 @@ -(void)trigger { } } --(void)coalesceForSeconds:(double)seconds { +- (void)coalesceForSeconds:(double)seconds { if (self.isCoallescing) { return; } self.isCoallescing = YES; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - if (self.isTriggered) { - self.block(); - } - self.isTriggered = NO; - self.isCoallescing = NO; - }); -} -@end // FlutterCoalescer + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC), + dispatch_get_main_queue(), ^{ + if (self.isTriggered) { + self.block(); + } + self.isTriggered = NO; + self.isCoallescing = NO; + }); +} +@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 From 1689375b1181f983e8ca7de6faee00cf76e992a6 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 30 Jan 2020 15:44:01 -0800 Subject: [PATCH 5/7] spelling mistake --- .../ios/framework/Source/FlutterViewController.mm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index d89319f874880..4646ed17ec13d 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -30,7 +30,7 @@ /// Class to coalesce calls for a period of time. @interface FlutterCoalescer : NSObject @property(nonatomic, assign) BOOL isTriggered; -@property(nonatomic, assign) BOOL isCoallescing; +@property(nonatomic, assign) BOOL isCoalescing; @property(nonatomic, copy) dispatch_block_t block; @end @@ -49,7 +49,7 @@ - (void)dealloc { } - (void)trigger { - if (_isCoallescing) { + if (_isCoalescing) { _isTriggered = YES; } else { _isTriggered = NO; @@ -58,17 +58,17 @@ - (void)trigger { } - (void)coalesceForSeconds:(double)seconds { - if (self.isCoallescing) { + if (self.isCoalescing) { return; } - self.isCoallescing = YES; + self.isCoalescing = YES; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ if (self.isTriggered) { self.block(); } self.isTriggered = NO; - self.isCoallescing = NO; + self.isCoalescing = NO; }); } @end // FlutterCoalescer From cdc2fc1ec75717b66f1fda8d3c5b2db55a99e698 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 30 Jan 2020 16:16:09 -0800 Subject: [PATCH 6/7] Made it so you can invalidate the coalescer. --- .../ios/framework/Source/FlutterViewController.mm | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 4646ed17ec13d..8b870eccdab50 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -53,24 +53,31 @@ - (void)trigger { _isTriggered = YES; } else { _isTriggered = NO; - _block(); + if (_block) { + _block(); + } } } - (void)coalesceForSeconds:(double)seconds { - if (self.isCoalescing) { + 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) { + 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 @@ -585,6 +592,7 @@ - (void)dealloc { userInfo:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [_ongoingTouches release]; + [_updateViewportMetrics invalidate]; [super dealloc]; } From 35be82811b2ffd116858de53f0943484ede19a81 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 31 Jan 2020 08:09:35 -0800 Subject: [PATCH 7/7] Added more info to the docstring for FlutterCoalescer. --- .../darwin/ios/framework/Source/FlutterViewController.mm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 8b870eccdab50..a94f6b657fa38 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -28,6 +28,9 @@ NSNotificationName const FlutterViewControllerWillDealloc = @"FlutterViewControllerWillDealloc"; /// 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;