diff --git a/lib/ui/window.dart b/lib/ui/window.dart index cc594cb580f..eceef0df62e 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -26,14 +26,43 @@ typedef void PlatformMessageResponseCallback(ByteData data); typedef void PlatformMessageCallback(String name, ByteData data, PlatformMessageResponseCallback callback); /// States that an application can be in. +/// +/// The values below describe notifications from the operating system. +/// Applications should not expect to always receive all possible +/// notifications. For example, if the users pulls out the battery from the +/// device, no notification will be sent before the application is suddenly +/// terminated, along with the rest of the operating system. enum AppLifecycleState { - /// The application is not currently visible to the user. When the - /// application is in this state, the engine will not call the + /// The application is visible and responding to user input. + resumed, + + /// The application is in an inactive state and is not receiving user input. + /// + /// On iOS, this state corresponds to an app running in the foreground + /// inactive state. Apps transition to this state when in a phone call, + /// responding to a TouchID request, or when entering the app switcher. Apps + /// in this state should assume that they may be [paused] at any time. + /// + /// On Android, this state is currently unused. + inactive, + + /// The application is not currently visible to the user, not responding to + /// user input, and running in the background. + /// + /// When the application is in this state, the engine will not call the /// [Window.onBeginFrame] and [Window.onDrawFrame] callbacks. + /// + /// Apps in this state should assume that they may be [suspended] at any + /// time. paused, - /// The application is visible to the user. - resumed, + /// The application will be suspended momentarily. + /// + /// When the application is in this state, the engine will not call the + /// [Window.onBeginFrame] and [Window.onDrawFrame] callbacks. + /// + /// On iOS, this state is currently unused. + suspending, } /// A representation of distances for each of the four edges of a rectangle, diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 7cd50574c0a..55a658bfb63 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -318,10 +318,12 @@ void Engine::DispatchPlatformMessage( bool Engine::HandleLifecyclePlatformMessage(blink::PlatformMessage* message) { const auto& data = message->data(); std::string state(reinterpret_cast(data.data()), data.size()); - if (state == "AppLifecycleState.paused") { + if (state == "AppLifecycleState.paused" || + state == "AppLifecycleState.suspending") { activity_running_ = false; StopAnimator(); - } else if (state == "AppLifecycleState.resumed") { + } else if (state == "AppLifecycleState.resumed" || + state == "AppLifecycle.inactive") { activity_running_ = true; StartAnimatorIfPossible(); } diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index c55c84d9688..e36b75e7860 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -213,6 +213,10 @@ public class FlutterView extends SurfaceView mFlutterLifecycleChannel.send("AppLifecycleState.resumed"); } + public void onStop() { + mFlutterLifecycleChannel.send("AppLifecycleState.suspending"); + } + public void onMemoryPressure() { Map message = new HashMap<>(1); message.put("type", "memoryPressure"); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 4c075fd35bb..3d740441862 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -189,6 +189,16 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { name:UIApplicationWillResignActiveNotification object:nil]; + [center addObserver:self + selector:@selector(applicationDidEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; + + [center addObserver:self + selector:@selector(applicationWillEnterForeground:) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + [center addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification @@ -261,9 +271,17 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { } - (void)applicationWillResignActive:(NSNotification*)notification { + [_lifecycleChannel.get() sendMessage:@"AppLifecycleState.inactive"]; +} + +- (void)applicationDidEnterBackground:(NSNotification*)notification { [_lifecycleChannel.get() sendMessage:@"AppLifecycleState.paused"]; } +- (void)applicationWillEnterForeground:(NSNotification*)notification { + [_lifecycleChannel.get() sendMessage:@"AppLifecycleState.inactive"]; +} + #pragma mark - Touch event handling enum MapperPhase {