From 07d214c391615c31cb6291ef7fea3eeade95d76d Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Sat, 27 May 2023 12:31:26 -0700 Subject: [PATCH] Revert "Adding app lifecycle notification for macOS and Linux, add `hidden` state. (#40542)" This reverts commit 9fd0082de8a9de77814493e3a8d25fe9b5384ab2. --- ci/licenses_golden/licenses_flutter | 8 - lib/ui/platform_dispatcher.dart | 135 ++++------- lib/web_ui/lib/platform_dispatcher.dart | 5 +- .../lib/src/engine/platform_dispatcher.dart | 9 - .../systemchannels/LifecycleChannel.java | 77 ++---- shell/platform/common/BUILD.gn | 5 +- shell/platform/common/app_lifecycle_state.h | 89 ------- shell/platform/darwin/macos/BUILD.gn | 3 - .../framework/Headers/FlutterAppDelegate.h | 19 +- .../Headers/FlutterAppLifecycleDelegate.h | 137 ----------- .../macos/framework/Headers/FlutterEngine.h | 4 +- .../macos/framework/Headers/FlutterMacOS.h | 1 - .../framework/Headers/FlutterPluginMacOS.h | 9 +- .../framework/Source/FlutterAppDelegate.mm | 17 +- .../Source/FlutterAppLifecycleDelegate.mm | 130 ---------- .../Source/FlutterAppLifecycleDelegateTest.mm | 223 ------------------ .../macos/framework/Source/FlutterEngine.mm | 84 +------ .../framework/Source/FlutterEngineTest.mm | 102 ++++---- .../framework/Source/FlutterEngine_Internal.h | 10 - shell/platform/linux/BUILD.gn | 2 - shell/platform/linux/fl_engine.cc | 35 --- shell/platform/linux/fl_engine_private.h | 12 - shell/platform/linux/fl_engine_test.cc | 38 --- shell/platform/linux/fl_view.cc | 47 +--- shell/platform/windows/BUILD.gn | 1 - .../windows/flutter_windows_engine.cc | 8 - .../platform/windows/flutter_windows_engine.h | 4 - tools/api_check/test/apicheck_test.dart | 34 +-- 28 files changed, 135 insertions(+), 1113 deletions(-) delete mode 100644 shell/platform/common/app_lifecycle_state.h delete mode 100644 shell/platform/darwin/macos/framework/Headers/FlutterAppLifecycleDelegate.h delete mode 100644 shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegate.mm delete mode 100644 shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegateTest.mm diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 7d0eab4a8cada..893d479e0dbe4 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2463,7 +2463,6 @@ ORIGIN: ../../../flutter/shell/platform/common/accessibility_bridge.cc + ../../. ORIGIN: ../../../flutter/shell/platform/common/accessibility_bridge.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/common/alert_platform_node_delegate.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/common/alert_platform_node_delegate.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/common/app_lifecycle_state.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/common/client_wrapper/binary_messenger_impl.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/common/client_wrapper/byte_buffer_streams.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/common/client_wrapper/core_implementations.cc + ../../../flutter/LICENSE @@ -2681,7 +2680,6 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/platform_view_ios.mm + ../../ ORIGIN: ../../../flutter/shell/platform/darwin/ios/rendering_api_selection.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/rendering_api_selection.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppLifecycleDelegate.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterMacOS.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterPlatformViews.h + ../../../flutter/LICENSE @@ -2693,8 +2691,6 @@ ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/Accessibil ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacTest.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppDelegate.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppDelegate_Internal.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegate.mm + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegateTest.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.h + ../../../flutter/LICENSE @@ -5134,7 +5130,6 @@ FILE: ../../../flutter/shell/platform/common/accessibility_bridge.cc FILE: ../../../flutter/shell/platform/common/accessibility_bridge.h FILE: ../../../flutter/shell/platform/common/alert_platform_node_delegate.cc FILE: ../../../flutter/shell/platform/common/alert_platform_node_delegate.h -FILE: ../../../flutter/shell/platform/common/app_lifecycle_state.h FILE: ../../../flutter/shell/platform/common/client_wrapper/binary_messenger_impl.h FILE: ../../../flutter/shell/platform/common/client_wrapper/byte_buffer_streams.h FILE: ../../../flutter/shell/platform/common/client_wrapper/core_implementations.cc @@ -5354,7 +5349,6 @@ FILE: ../../../flutter/shell/platform/darwin/ios/platform_view_ios.mm FILE: ../../../flutter/shell/platform/darwin/ios/rendering_api_selection.h FILE: ../../../flutter/shell/platform/darwin/ios/rendering_api_selection.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h -FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppLifecycleDelegate.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterMacOS.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterPlatformViews.h @@ -5367,8 +5361,6 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/Accessibilit FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacTest.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppDelegate.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppDelegate_Internal.h -FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegate.mm -FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegateTest.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.h diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index 42a56a36c345a..0e26b0ca215a1 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -1679,15 +1679,13 @@ class FrameTiming { } } -/// States that an application can be in once it is running. +/// States that an application can be in. /// -/// States not supported on a platform will be synthesized by the framework when -/// transitioning between states which are supported, so that all -/// implementations share the same state machine. -/// -/// The initial value for the state is the [detached] state, updated to the -/// current state (usually [resumed]) as soon as the first lifecycle update is -/// received from the platform. +/// 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. /// /// For historical and name collision reasons, Flutter's application state names /// do not correspond one to one with the state names on all platforms. On @@ -1698,52 +1696,15 @@ class FrameTiming { /// Flutter enters the [paused] state. See the individual state's documentation /// for descriptions of what they mean on each platform. /// -/// The current application state can be obtained from -/// [SchedulerBinding.instance.lifecycleState], and changes to the state can be -/// observed by creating an [AppLifecycleListener], or by using a -/// [WidgetsBindingObserver] by overriding the -/// [WidgetsBindingObserver.didChangeAppLifecycleState] method. -/// -/// Applications should not rely on always receiving all possible notifications. -/// -/// For example, if the application is killed with a task manager, a kill -/// signal, the user pulls the power from the device, or there is a rapid -/// unscheduled disassembly of the device, no notification will be sent before -/// the application is suddenly terminated, and some states may be skipped. -/// /// See also: /// -/// * [AppLifecycleListener], an object used observe the lifecycle state that -/// provides state transition callbacks. /// * [WidgetsBindingObserver], for a mechanism to observe the lifecycle state /// from the widgets layer. -/// * iOS's [IOKit activity -/// lifecycle](https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle?language=objc) -/// documentation. -/// * Android's [activity -/// lifecycle](https://developer.android.com/guide/components/activities/activity-lifecycle) -/// documentation. -/// * macOS's [AppKit activity -/// lifecycle](https://developer.apple.com/documentation/appkit/nsapplicationdelegate?language=objc) -/// documentation. +/// * iOS's [IOKit activity lifecycle](https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle?language=objc) documentation. +/// * Android's [activity lifecycle](https://developer.android.com/guide/components/activities/activity-lifecycle) documentation. +/// * macOS's [AppKit activity lifecycle](https://developer.apple.com/documentation/appkit/nsapplicationdelegate?language=objc) documentation. enum AppLifecycleState { - /// The application is still hosted by a Flutter engine but is detached from - /// any host views. - /// - /// The application defaults to this state before it initializes, and can be - /// in this state (on Android and iOS only) after all views have been - /// detached. - /// - /// When the application is in this state, the engine is running without a - /// view. - /// - /// This state is only entered on iOS and Android, although on all platforms - /// it is the default state before the application begins running. - detached, - - /// On all platforms, this state indicates that the application is in the - /// default running mode for a running application that has input focus and is - /// visible. + /// The application is visible and responsive to user input. /// /// On Android, this state corresponds to the Flutter host view having focus /// ([`Activity.onWindowFocusChanged`](https://developer.android.com/reference/android/app/Activity#onWindowFocusChanged(boolean)) @@ -1756,71 +1717,54 @@ enum AppLifecycleState { /// was called with false), but hasn't had /// [`Activity.onPause`](https://developer.android.com/reference/android/app/Activity#onPause()) /// called on it. - /// - /// On iOS and macOS, this corresponds to the app running in the foreground - /// active state. resumed, - /// At least one view of the application is visible, but none have input - /// focus. The application is otherwise running normally. - /// - /// On non-web desktop platforms, this corresponds to an application that is - /// not in the foreground, but still has visible windows. - /// - /// On the web, this corresponds to an application that is running in a - /// window or tab that does not have input focus. + /// The application is in an inactive state and is not receiving user input. /// - /// On iOS and macOS, this state corresponds to the Flutter host view running in the - /// foreground inactive state. Apps transition to this state when in a phone - /// call, when responding to a TouchID request, when entering the app switcher - /// or the control center, or when the UIViewController hosting the Flutter - /// app is transitioning. + /// On iOS, this state corresponds to an app or the Flutter host view running + /// in the foreground inactive state. Apps transition to this state when in a + /// phone call, responding to a TouchID request, when entering the app + /// switcher or the control center, or when the UIViewController hosting the + /// Flutter app is transitioning. /// - /// On Android, this corresponds to the Flutter host view running in Android's - /// paused state (i.e. + /// On Android, this corresponds to an app or the Flutter host view running in + /// Android's paused state (i.e. /// [`Activity.onPause`](https://developer.android.com/reference/android/app/Activity#onPause()) /// has been called), or in Android's "resumed" state (i.e. /// [`Activity.onResume`](https://developer.android.com/reference/android/app/Activity#onResume()) - /// has been called) but does not have window focus. Examples of when apps + /// has been called) but it has lost window focus. Examples of when apps /// transition to this state include when the app is partially obscured or - /// another activity is focused, a app running in a split screen that isn't - /// the current app, an app interrupted by a phone call, a picture-in-picture - /// app, a system dialog, another view. It will also be inactive when the + /// another activity is focused, such as: a split-screen app, a phone call, a + /// picture-in-picture app, a system dialog, another view, when the /// notification window shade is down, or the application switcher is visible. /// - /// On Android and iOS, apps in this state should assume that they may be - /// [hidden] and [paused] at any time. + /// Apps in this state should assume that they may be [paused] at any time. inactive, - /// All views of an application are hidden, either because the application is - /// about to be paused (on iOS and Android), or because it has been minimized - /// or placed on a desktop that is no longer visible (on non-web desktop), or - /// is running in a window or tab that is no longer visible (on the web). - /// - /// On iOS and Android, in order to keep the state machine the same on all - /// platforms, a transition to this state is synthesized before the [paused] - /// state is entered when coming from [inactive], and before the [inactive] - /// state is entered when coming from [paused]. This allows cross-platform - /// implementations that want to know when an app is conceptually "hidden" to - /// only write one handler. - hidden, - - /// The application is not currently visible to the user, and not responding - /// to user input. + /// 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 /// [PlatformDispatcher.onBeginFrame] and [PlatformDispatcher.onDrawFrame] /// callbacks. - /// - /// This state is only entered on iOS and Android. paused, + + /// The application is still hosted on a flutter engine but is detached from + /// any host views. + /// + /// When the application is in this state, the engine is running without + /// a view. It can either be in the progress of attaching a view when engine + /// was first initializes, or after the view being destroyed due to a Navigator + /// pop. + detached, } /// The possible responses to a request to exit the application. /// -/// The request is typically responded to by creating an [AppLifecycleListener] -/// and supplying an [AppLifecycleListener.onExitRequested] callback, or by -/// overriding [WidgetsBindingObserver.didRequestAppExit]. +/// The request is typically responded to by a [WidgetsBindingObserver]. +// TODO(gspencergoog): Insert doc references here to AppLifecycleListener and to +// the actual function called on WidgetsBindingObserver once those have landed +// in the framework. https://github.com/flutter/flutter/issues/121721 enum AppExitResponse { /// Exiting the application can proceed. exit, @@ -1829,7 +1773,10 @@ enum AppExitResponse { } /// The type of application exit to perform when calling -/// [ServicesBinding.exitApplication]. +/// `ServicesBinding.exitApplication`. +// TODO(gspencergoog): Insert doc references here to +// ServicesBinding.exitApplication that has landed in the framework. +// https://github.com/flutter/flutter/issues/121721 enum AppExitType { /// Requests that the application start an orderly exit, sending a request /// back to the framework through the [WidgetsBinding]. If that responds diff --git a/lib/web_ui/lib/platform_dispatcher.dart b/lib/web_ui/lib/platform_dispatcher.dart index 2059122d8c8a5..2546404fbacce 100644 --- a/lib/web_ui/lib/platform_dispatcher.dart +++ b/lib/web_ui/lib/platform_dispatcher.dart @@ -104,7 +104,7 @@ abstract class PlatformDispatcher { VoidCallback? get onLocaleChanged; set onLocaleChanged(VoidCallback? callback); - String get initialLifecycleState => ''; + String get initialLifecycleState => 'AppLifecycleState.resumed'; bool get alwaysUse24HourFormat; @@ -247,11 +247,10 @@ class FrameTiming { } enum AppLifecycleState { - detached, resumed, inactive, - hidden, paused, + detached, } enum AppExitResponse { diff --git a/lib/web_ui/lib/src/engine/platform_dispatcher.dart b/lib/web_ui/lib/src/engine/platform_dispatcher.dart index 0d54cba677de7..7ff4c674121f4 100644 --- a/lib/web_ui/lib/src/engine/platform_dispatcher.dart +++ b/lib/web_ui/lib/src/engine/platform_dispatcher.dart @@ -104,7 +104,6 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { _addFontSizeObserver(); _addLocaleChangedListener(); registerHotRestartListener(dispose); - _setAppLifecycleState(ui.AppLifecycleState.resumed); } /// The [EnginePlatformDispatcher] singleton. @@ -1006,14 +1005,6 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { _fontSizeObserver = null; } - void _setAppLifecycleState(ui.AppLifecycleState state) { - sendPlatformMessage( - 'flutter/lifecycle', - Uint8List.fromList(utf8.encode(state.toString())).buffer.asByteData(), - null, - ); - } - /// A callback that is invoked whenever [textScaleFactor] changes value. /// /// The framework invokes this callback in the same zone in which the diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java index 2e6858baf67f6..6ea0814fe0ba5 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java @@ -22,21 +22,14 @@ public class LifecycleChannel { private static final String TAG = "LifecycleChannel"; private static final String CHANNEL_NAME = "flutter/lifecycle"; - // This enum should match the Dart enum of the same name. - // - // HIDDEN isn't used on Android (it's synthesized in the Framework code). It's - // only listed here so that apicheck_test.dart can make sure that the states here - // match the Dart code. - private enum AppLifecycleState { - DETACHED, - RESUMED, - INACTIVE, - HIDDEN, - PAUSED, - }; - - private AppLifecycleState lastAndroidState = null; - private AppLifecycleState lastFlutterState = null; + // These should stay in sync with the AppLifecycleState enum in the framework. + private static final String RESUMED = "AppLifecycleState.resumed"; + private static final String INACTIVE = "AppLifecycleState.inactive"; + private static final String PAUSED = "AppLifecycleState.paused"; + private static final String DETACHED = "AppLifecycleState.detached"; + + private String lastAndroidState = ""; + private String lastFlutterState = ""; private boolean lastFocus = true; @NonNull private final BasicMessageChannel channel; @@ -62,39 +55,21 @@ public LifecycleChannel(@NonNull BasicMessageChannel channel) { // | Stopped | false | paused | // | Detached | true | detached | // | Detached | false | detached | - // - // The hidden state isn't used on Android, it's synthesized in the Framework - // code when transitioning between paused and inactive in either direction. - private void sendState(AppLifecycleState state, boolean hasFocus) { + private void sendState(String state, boolean hasFocus) { if (lastAndroidState == state && hasFocus == lastFocus) { // No inputs changed, so Flutter state could not have changed. return; } - if (state == null && lastAndroidState == null) { - // If we're responding to a focus change before the state is set, just - // keep the last reported focus state and don't send anything to the - // framework. This could happen if focus events and lifecycle events are - // delivered out of the expected order. - lastFocus = hasFocus; - return; - } - AppLifecycleState newState = null; - switch (state) { - case RESUMED: - // Focus is only taken into account when the Android state is "Resumed". - // In all other states, focus is ignored, because we can't know what order - // Android lifecycle notifications and window focus notifications events - // will arrive in, and those states don't send input events anyhow. - newState = hasFocus ? AppLifecycleState.RESUMED : AppLifecycleState.INACTIVE; - break; - case INACTIVE: - case HIDDEN: - case PAUSED: - case DETACHED: - newState = state; - break; + String newState; + if (state == RESUMED) { + // Focus is only taken into account when the Android state is "Resumed". + // In all other states, focus is ignored, because we can't know what order + // Android lifecycle notifications and window focus notifications events + // will arrive in, and those states don't send input events anyhow. + newState = hasFocus ? RESUMED : INACTIVE; + } else { + newState = state; } - // Keep the last reported values for future updates. lastAndroidState = state; lastFocus = hasFocus; @@ -102,14 +77,12 @@ private void sendState(AppLifecycleState state, boolean hasFocus) { // No change in the resulting Flutter state, so don't report anything. return; } - String message = "AppLifecycleState." + newState.name().toLowerCase(); - Log.v(TAG, "Sending " + message + " message."); - channel.send(message); + Log.v(TAG, "Sending " + newState + " message."); + channel.send(newState); lastFlutterState = newState; } - // Called if at least one window in the app has focus, even if the focused - // window doesn't contain a Flutter view. + // Called if at least one window in the app has focus. public void aWindowIsFocused() { sendState(lastAndroidState, true); } @@ -120,18 +93,18 @@ public void noWindowsAreFocused() { } public void appIsResumed() { - sendState(AppLifecycleState.RESUMED, lastFocus); + sendState(RESUMED, lastFocus); } public void appIsInactive() { - sendState(AppLifecycleState.INACTIVE, lastFocus); + sendState(INACTIVE, lastFocus); } public void appIsPaused() { - sendState(AppLifecycleState.PAUSED, lastFocus); + sendState(PAUSED, lastFocus); } public void appIsDetached() { - sendState(AppLifecycleState.DETACHED, lastFocus); + sendState(DETACHED, lastFocus); } } diff --git a/shell/platform/common/BUILD.gn b/shell/platform/common/BUILD.gn index 13f2a51e20e97..0d45a8ad1eb5f 100644 --- a/shell/platform/common/BUILD.gn +++ b/shell/platform/common/BUILD.gn @@ -58,10 +58,7 @@ source_set("common_cpp_input") { } source_set("common_cpp_enums") { - public = [ - "app_lifecycle_state.h", - "platform_provided_menu.h", - ] + public = [ "platform_provided_menu.h" ] public_configs = [ "//flutter:config", diff --git a/shell/platform/common/app_lifecycle_state.h b/shell/platform/common/app_lifecycle_state.h deleted file mode 100644 index a3d79dcb74c81..0000000000000 --- a/shell/platform/common/app_lifecycle_state.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_SHELL_PLATFORM_COMMON_APP_LIFECYCLE_STATE_H_ -#define FLUTTER_SHELL_PLATFORM_COMMON_APP_LIFECYCLE_STATE_H_ - -namespace flutter { - -/** - * These constants describe the possible lifecycle states of the application. - * They must be kept up to date with changes in the framework's - * AppLifecycleState enum. They are passed to the embedder's |SetLifecycleState| - * function. - * - * States not supported on a platform will be synthesized by the framework when - * transitioning between states which are supported, so that all implementations - * share the same state machine. - * - * Here is the state machine: - * - * +-----------+ +-----------+ - * | detached |------------------------------>| resumed | - * +-----------+ +-----------+ - * ^ ^ - * | | - * | v - * +-----------+ +--------------+ +-----------+ - * | paused |<------>| hidden |<----->| inactive | - * +-----------+ +--------------+ +-----------+ - */ -enum class AppLifecycleState { - /** - * Corresponds to the Framework's AppLifecycleState.detached: The initial - * state of the state machine. On Android and iOS, also the final state of the - * state machine when all views are detached. Other platforms do not enter - * this state again after initially leaving it. - */ - kDetached, - - /** - * Corresponds to the Framework's AppLifecycleState.resumed: The nominal - * "running" state of the application. The application is visible, has input - * focus, and is running. - */ - kResumed, - - /** - * Corresponds to the Framework's AppLifecycleState.inactive: At least one - * view of the application is visible, but none have input focus. The - * application is otherwise running normally. - */ - kInactive, - - /** - * Corresponds to the Framework's AppLifecycleState.hidden: All views of an - * application are hidden, either because the application is being stopped (on - * iOS and Android), or because it is being minimized or on a desktop that is - * no longer visible (on desktop), or on a tab that is no longer visible (on - * web). - */ - kHidden, - - /** - * Corresponds to the Framework's AppLifecycleState.paused: The application is - * not running, and can be detached or started again at any time. This state - * is typically only entered into on iOS and Android. - */ - kPaused, -}; - -constexpr const char* AppLifecycleStateToString(AppLifecycleState state) { - switch (state) { - case AppLifecycleState::kDetached: - return "AppLifecycleState.detached"; - case AppLifecycleState::kResumed: - return "AppLifecycleState.resumed"; - case AppLifecycleState::kInactive: - return "AppLifecycleState.inactive"; - case AppLifecycleState::kHidden: - return "AppLifecycleState.hidden"; - case AppLifecycleState::kPaused: - return "AppLifecycleState.paused"; - } -} - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_COMMON_APP_LIFECYCLE_STATE_H_ diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index 86f681b21fe57..16ffb24cd3f19 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -38,7 +38,6 @@ _framework_binary_subpath = "Versions/A/$_flutter_framework_name" # the Flutter engine source root. _flutter_framework_headers = [ "framework/Headers/FlutterAppDelegate.h", - "framework/Headers/FlutterAppLifecycleDelegate.h", "framework/Headers/FlutterEngine.h", "framework/Headers/FlutterMacOS.h", "framework/Headers/FlutterPlatformViews.h", @@ -57,7 +56,6 @@ source_set("flutter_framework_source") { "framework/Source/AccessibilityBridgeMac.h", "framework/Source/AccessibilityBridgeMac.mm", "framework/Source/FlutterAppDelegate.mm", - "framework/Source/FlutterAppLifecycleDelegate.mm", "framework/Source/FlutterBackingStore.h", "framework/Source/FlutterBackingStore.mm", "framework/Source/FlutterChannelKeyResponder.h", @@ -169,7 +167,6 @@ executable("flutter_desktop_darwin_unittests") { sources = [ "framework/Source/AccessibilityBridgeMacTest.mm", - "framework/Source/FlutterAppLifecycleDelegateTest.mm", "framework/Source/FlutterChannelKeyResponderTest.mm", "framework/Source/FlutterCompositorTest.mm", "framework/Source/FlutterEmbedderExternalTextureTest.mm", diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h b/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h index c7aaeca37e6cc..092c0115d077f 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h @@ -7,11 +7,10 @@ #import -#import "FlutterAppLifecycleDelegate.h" #import "FlutterMacros.h" /** - * |NSApplicationDelegate| subclass for simple apps that want default behavior. + * `NSApplicationDelegate` subclass for simple apps that want default behavior. * * This class implements the following behaviors: * * Updates the application name of items in the application menu to match the name in @@ -34,23 +33,11 @@ FLUTTER_DARWIN_EXPORT @property(weak, nonatomic) IBOutlet NSMenu* applicationMenu; /** - * The primary application window containing a FlutterViewController. This is - * primarily intended for use in single-window applications. + * The primary application window containing a FlutterViewController. This is primarily intended + * for use in single-window applications. */ @property(weak, nonatomic) IBOutlet NSWindow* mainFlutterWindow; -/** - * Adds an object implementing |FlutterAppLifecycleDelegate| to the list of - * delegates to be informed of application lifecycle events. - */ -- (void)addApplicationLifecycleDelegate:(NSObject*)delegate; - -/** - * Removes an object implementing |FlutterAppLifecycleDelegate| to the list of - * delegates to be informed of application lifecycle events. - */ -- (void)removeApplicationLifecycleDelegate:(NSObject*)delegate; - @end #endif // FLUTTER_FLUTTERAPPDELEGATE_H_ diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterAppLifecycleDelegate.h b/shell/platform/darwin/macos/framework/Headers/FlutterAppLifecycleDelegate.h deleted file mode 100644 index fd8d52de20e52..0000000000000 --- a/shell/platform/darwin/macos/framework/Headers/FlutterAppLifecycleDelegate.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_FLUTTERAPPLIFECYCLEDELEGATE_H_ -#define FLUTTER_FLUTTERAPPLIFECYCLEDELEGATE_H_ - -#import -#include - -#import "FlutterMacros.h" -#import "FlutterPluginMacOS.h" - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - -/** - * Protocol for listener of lifecycle events from the NSApplication, typically a - * FlutterPlugin. - */ -@protocol FlutterAppLifecycleDelegate - -@optional -/** - * Called when the |FlutterAppDelegate| gets the applicationWillFinishLaunching - * notification. - */ -- (void)handleWillFinishLaunching:(NSNotification*)notification; - -/** - * Called when the |FlutterAppDelegate| gets the applicationDidFinishLaunching - * notification. - */ -- (void)handleDidFinishLaunching:(NSNotification*)notification; - -/** - * Called when the |FlutterAppDelegate| gets the applicationWillBecomeActive - * notification. - */ -- (void)handleWillBecomeActive:(NSNotification*)notification; - -/** - * Called when the |FlutterAppDelegate| gets the applicationDidBecomeActive - * notification. - */ -- (void)handleDidBecomeActive:(NSNotification*)notification; - -/** - * Called when the |FlutterAppDelegate| gets the applicationWillResignActive - * notification. - */ -- (void)handleWillResignActive:(NSNotification*)notification; - -/** - * Called when the |FlutterAppDelegate| gets the applicationWillResignActive - * notification. - */ -- (void)handleDidResignActive:(NSNotification*)notification; - -/** - * Called when the |FlutterAppDelegate| gets the applicationWillHide - * notification. - */ -- (void)handleWillHide:(NSNotification*)notification; - -/** - * Called when the |FlutterAppDelegate| gets the applicationDidHide - * notification. - */ -- (void)handleDidHide:(NSNotification*)notification; - -/** - * Called when the |FlutterAppDelegate| gets the applicationWillUnhide - * notification. - */ -- (void)handleWillUnhide:(NSNotification*)notification; - -/** - * Called when the |FlutterAppDelegate| gets the applicationDidUnhide - * notification. - */ -- (void)handleDidUnhide:(NSNotification*)notification; - -/** - * Called when the |FlutterAppDelegate| gets the applicationDidUnhide - * notification. - */ -- (void)handleDidChangeScreenParameters:(NSNotification*)notification; - -/** - * Called when the |FlutterAppDelegate| gets the applicationDidUnhide - * notification. - */ -- (void)handleDidChangeOcclusionState:(NSNotification*)notification API_AVAILABLE(macos(10.9)); - -/** - * Called when the |FlutterAppDelegate| gets the applicationWillTerminate - * notification. - * - * Applications should not rely on always receiving all possible notifications. - * - * For example, if the application is killed with a task manager, a kill signal, - * the user pulls the power from the device, or there is a rapid unscheduled - * disassembly of the device, no notification will be sent before the - * application is suddenly terminated, and this notification may be skipped. - */ -- (void)handleWillTerminate:(NSNotification*)notification; -@end - -#pragma mark - - -/** - * Propagates `NSAppDelegate` callbacks to registered delegates. - */ -FLUTTER_DARWIN_EXPORT -@interface FlutterAppLifecycleRegistrar : NSObject - -/** - * Registers `delegate` to receive lifecycle callbacks via this - * FlutterAppLifecycleDelegate as long as it is alive. - * - * `delegate` will only be referenced weakly. - */ -- (void)addDelegate:(NSObject*)delegate; - -/** - * Unregisters `delegate` so that it will no longer receive life cycle callbacks - * via this FlutterAppLifecycleDelegate. - * - * `delegate` will only be referenced weakly. - */ -- (void)removeDelegate:(NSObject*)delegate; -@end - -NS_ASSUME_NONNULL_END - -#endif // FLUTTER_FLUTTERAPPLIFECYCLEDELEGATE_H_ diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h b/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h index bb12d5cd2ae76..f854976ebd611 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h @@ -9,7 +9,6 @@ #include -#import "FlutterAppLifecycleDelegate.h" #import "FlutterBinaryMessenger.h" #import "FlutterDartProject.h" #import "FlutterMacros.h" @@ -27,8 +26,7 @@ * code. */ FLUTTER_DARWIN_EXPORT -@interface FlutterEngine - : NSObject +@interface FlutterEngine : NSObject /** * Initializes an engine with the given project. diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterMacOS.h b/shell/platform/darwin/macos/framework/Headers/FlutterMacOS.h index a7753e578a3fd..5fc794b92995d 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterMacOS.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterMacOS.h @@ -3,7 +3,6 @@ // found in the LICENSE file. #import "FlutterAppDelegate.h" -#import "FlutterAppLifecycleDelegate.h" #import "FlutterBinaryMessenger.h" #import "FlutterChannels.h" #import "FlutterCodecs.h" diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterPluginMacOS.h b/shell/platform/darwin/macos/framework/Headers/FlutterPluginMacOS.h index af8e0dd686a25..cbedb0566a767 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterPluginMacOS.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterPluginMacOS.h @@ -8,7 +8,8 @@ #import "FlutterCodecs.h" #import "FlutterMacros.h" -NS_ASSUME_NONNULL_BEGIN +// TODO: Merge this file and FlutterPluginRegistrarMacOS.h with the iOS FlutterPlugin.h, sharing +// all but the platform-specific methods. @protocol FlutterPluginRegistrar; @@ -28,7 +29,7 @@ FLUTTER_DARWIN_EXPORT * Creates an instance of the plugin to register with |registrar| using the desired * FlutterPluginRegistrar methods. */ -+ (void)registerWithRegistrar:(id)registrar; ++ (void)registerWithRegistrar:(nonnull id)registrar; @optional @@ -43,8 +44,6 @@ FLUTTER_DARWIN_EXPORT * - Any other value (including nil) to indicate success. The value will * be returned to the Flutter caller, and must be serializable to JSON. */ -- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result; - -NS_ASSUME_NONNULL_END +- (void)handleMethodCall:(nonnull FlutterMethodCall*)call result:(nonnull FlutterResult)result; @end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterAppDelegate.mm b/shell/platform/darwin/macos/framework/Source/FlutterAppDelegate.mm index 782266419edba..e934c0a6b663e 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterAppDelegate.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterAppDelegate.mm @@ -8,7 +8,6 @@ #import #include "flutter/fml/logging.h" -#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppLifecycleDelegate.h" #include "flutter/shell/platform/embedder/embedder.h" @interface FlutterAppDelegate () @@ -18,15 +17,17 @@ @interface FlutterAppDelegate () */ - (NSString*)applicationName; -@property(nonatomic) FlutterAppLifecycleRegistrar* lifecycleRegistrar; @end @implementation FlutterAppDelegate +// TODO(gspencergoog): Implement application lifecycle forwarding to plugins here, as is done +// on iOS. Currently macOS plugins don't have access to lifecycle messages. +// https://github.com/flutter/flutter/issues/30735 + - (instancetype)init { if (self = [super init]) { _terminationHandler = nil; - _lifecycleRegistrar = [[FlutterAppLifecycleRegistrar alloc] init]; } return self; } @@ -41,16 +42,6 @@ - (void)applicationWillFinishLaunching:(NSNotification*)notification { } } -#pragma mark - Delegate handling - -- (void)addApplicationLifecycleDelegate:(NSObject*)delegate { - [[self lifecycleRegistrar] addDelegate:delegate]; -} - -- (void)removeApplicationLifecycleDelegate:(NSObject*)delegate { - [[self lifecycleRegistrar] removeDelegate:delegate]; -} - #pragma mark Private Methods - (NSString*)applicationName { diff --git a/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegate.mm b/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegate.mm deleted file mode 100644 index 4b552b94ca1a0..0000000000000 --- a/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegate.mm +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppLifecycleDelegate.h" - -#include -#include -#include -#include - -#include "flutter/fml/logging.h" -#include "flutter/fml/paths.h" - -@interface FlutterAppLifecycleRegistrar () -@end - -@implementation FlutterAppLifecycleRegistrar { - NSMutableArray* _notificationUnsubscribers; - - // Weak references to registered plugins. - NSPointerArray* _delegates; -} - -- (void)addObserverFor:(NSString*)name selector:(SEL)selector { - [[NSNotificationCenter defaultCenter] addObserver:self selector:selector name:name object:nil]; - __block NSObject* blockSelf = self; - dispatch_block_t unsubscribe = ^{ - [[NSNotificationCenter defaultCenter] removeObserver:blockSelf name:name object:nil]; - }; - [_notificationUnsubscribers addObject:[unsubscribe copy]]; -} - -- (instancetype)init { - if (self = [super init]) { - _notificationUnsubscribers = [[NSMutableArray alloc] init]; - -// Using a macro to avoid errors where the notification doesn't match the -// selector. -#ifdef OBSERVE_NOTIFICATION -#error OBSERVE_NOTIFICATION ALREADY DEFINED! -#else -#define OBSERVE_NOTIFICATION(SELECTOR) \ - [self addObserverFor:NSApplication##SELECTOR##Notification selector:@selector(handle##SELECTOR:)] -#endif - - OBSERVE_NOTIFICATION(WillFinishLaunching); - OBSERVE_NOTIFICATION(DidFinishLaunching); - OBSERVE_NOTIFICATION(WillBecomeActive); - OBSERVE_NOTIFICATION(DidBecomeActive); - OBSERVE_NOTIFICATION(WillResignActive); - OBSERVE_NOTIFICATION(DidResignActive); - OBSERVE_NOTIFICATION(WillTerminate); - OBSERVE_NOTIFICATION(WillHide); - OBSERVE_NOTIFICATION(DidHide); - OBSERVE_NOTIFICATION(WillUnhide); - OBSERVE_NOTIFICATION(DidUnhide); - OBSERVE_NOTIFICATION(DidChangeScreenParameters); - OBSERVE_NOTIFICATION(DidChangeOcclusionState); - -#undef OBSERVE_NOTIFICATION - - _delegates = [NSPointerArray weakObjectsPointerArray]; - } - return self; -} - -- (void)dealloc { - for (dispatch_block_t unsubscribe in _notificationUnsubscribers) { - unsubscribe(); - } - [_notificationUnsubscribers removeAllObjects]; - _delegates = nil; - _notificationUnsubscribers = nil; -} - -static BOOL IsPowerOfTwo(NSUInteger x) { - return x != 0 && (x & (x - 1)) == 0; -} - -- (void)addDelegate:(NSObject*)delegate { - [_delegates addPointer:(__bridge void*)delegate]; - if (IsPowerOfTwo([_delegates count])) { - [_delegates compact]; - } -} - -- (void)removeDelegate:(NSObject*)delegate { - NSUInteger index = [[_delegates allObjects] indexOfObject:delegate]; - if (index >= 0) { - [_delegates removePointerAtIndex:index]; - } -} - -// This isn't done via performSelector because that can cause leaks due to the -// selector not being known. Using a macro to avoid mismatch errors between the -// notification and the selector. -#ifdef DISTRIBUTE_NOTIFICATION -#error DISTRIBUTE_NOTIFICATION ALREADY DEFINED! -#else -#define DISTRIBUTE_NOTIFICATION(SELECTOR) \ - -(void)handle##SELECTOR : (NSNotification*)notification { \ - for (NSObject * delegate in _delegates) { \ - if (!delegate) { \ - continue; \ - } \ - if ([delegate respondsToSelector:@selector(handle##SELECTOR:)]) { \ - [delegate handle##SELECTOR:notification]; \ - } \ - } \ - } -#endif - -DISTRIBUTE_NOTIFICATION(WillFinishLaunching) -DISTRIBUTE_NOTIFICATION(DidFinishLaunching) -DISTRIBUTE_NOTIFICATION(WillBecomeActive) -DISTRIBUTE_NOTIFICATION(DidBecomeActive) -DISTRIBUTE_NOTIFICATION(WillResignActive) -DISTRIBUTE_NOTIFICATION(DidResignActive) -DISTRIBUTE_NOTIFICATION(WillTerminate) -DISTRIBUTE_NOTIFICATION(WillHide) -DISTRIBUTE_NOTIFICATION(WillUnhide) -DISTRIBUTE_NOTIFICATION(DidHide) -DISTRIBUTE_NOTIFICATION(DidUnhide) -DISTRIBUTE_NOTIFICATION(DidChangeScreenParameters) -DISTRIBUTE_NOTIFICATION(DidChangeOcclusionState) - -#undef DISTRIBUTE_NOTIFICATION - -@end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegateTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegateTest.mm deleted file mode 100644 index 079ddbb7ff26b..0000000000000 --- a/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegateTest.mm +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppLifecycleDelegate.h" - -#import "flutter/testing/testing.h" -#include "third_party/googletest/googletest/include/gtest/gtest.h" - -@interface TestFlutterAppLifecycleDelegate : NSObject -@property(nonatomic, readwrite, nullable) NSNotification* lastNotification; -@end - -@implementation TestFlutterAppLifecycleDelegate - -- (void)setNotification:(NSNotification*)notification { - self.lastNotification = notification; -} - -- (void)handleWillFinishLaunching:(NSNotification*)notification { - [self setNotification:notification]; -} - -- (void)handleDidFinishLaunching:(NSNotification*)notification { - [self setNotification:notification]; -} - -- (void)handleWillBecomeActive:(NSNotification*)notification { - [self setNotification:notification]; -} - -- (void)handleDidBecomeActive:(NSNotification*)notification { - [self setNotification:notification]; -} - -- (void)handleWillResignActive:(NSNotification*)notification { - [self setNotification:notification]; -} - -- (void)handleDidResignActive:(NSNotification*)notification { - [self setNotification:notification]; -} - -- (void)handleWillHide:(NSNotification*)notification { - [self setNotification:notification]; -} - -- (void)handleDidHide:(NSNotification*)notification { - [self setNotification:notification]; -} - -- (void)handleWillUnhide:(NSNotification*)notification { - [self setNotification:notification]; -} - -- (void)handleDidUnhide:(NSNotification*)notification { - [self setNotification:notification]; -} - -- (void)handleDidChangeScreenParameters:(NSNotification*)notification { - [self setNotification:notification]; -} - -- (void)handleDidChangeOcclusionState:(NSNotification*)notification API_AVAILABLE(macos(10.9)) { - [self setNotification:notification]; -} - -- (void)handleWillTerminate:(NSNotification*)notification { - [self setNotification:notification]; -} - -@end - -namespace flutter::testing { - -TEST(FlutterAppLifecycleDelegateTest, RespondsToWillFinishLaunching) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* willFinishLaunching = - [NSNotification notificationWithName:NSApplicationWillFinishLaunchingNotification object:nil]; - [registrar handleWillFinishLaunching:willFinishLaunching]; - EXPECT_EQ([delegate lastNotification], willFinishLaunching); -} - -TEST(FlutterAppLifecycleDelegateTest, RespondsToDidFinishLaunching) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* didFinishLaunching = - [NSNotification notificationWithName:NSApplicationDidFinishLaunchingNotification object:nil]; - [registrar handleDidFinishLaunching:didFinishLaunching]; - EXPECT_EQ([delegate lastNotification], didFinishLaunching); -} - -TEST(FlutterAppLifecycleDelegateTest, RespondsToWillBecomeActive) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* willBecomeActive = - [NSNotification notificationWithName:NSApplicationWillBecomeActiveNotification object:nil]; - [registrar handleWillBecomeActive:willBecomeActive]; - EXPECT_EQ([delegate lastNotification], willBecomeActive); -} - -TEST(FlutterAppLifecycleDelegateTest, RespondsToDidBecomeActive) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* didBecomeActive = - [NSNotification notificationWithName:NSApplicationDidBecomeActiveNotification object:nil]; - [registrar handleDidBecomeActive:didBecomeActive]; - EXPECT_EQ([delegate lastNotification], didBecomeActive); -} - -TEST(FlutterAppLifecycleDelegateTest, RespondsToWillResignActive) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* willResignActive = - [NSNotification notificationWithName:NSApplicationWillResignActiveNotification object:nil]; - [registrar handleWillResignActive:willResignActive]; - EXPECT_EQ([delegate lastNotification], willResignActive); -} - -TEST(FlutterAppLifecycleDelegateTest, RespondsToDidResignActive) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* didResignActive = - [NSNotification notificationWithName:NSApplicationDidResignActiveNotification object:nil]; - [registrar handleDidResignActive:didResignActive]; - EXPECT_EQ([delegate lastNotification], didResignActive); -} - -TEST(FlutterAppLifecycleDelegateTest, RespondsToWillTerminate) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* applicationWillTerminate = - [NSNotification notificationWithName:NSApplicationWillTerminateNotification object:nil]; - [registrar handleWillTerminate:applicationWillTerminate]; - EXPECT_EQ([delegate lastNotification], applicationWillTerminate); -} - -TEST(FlutterAppLifecycleDelegateTest, RespondsToWillHide) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* willHide = [NSNotification notificationWithName:NSApplicationWillHideNotification - object:nil]; - [registrar handleWillHide:willHide]; - EXPECT_EQ([delegate lastNotification], willHide); -} - -TEST(FlutterAppLifecycleDelegateTest, RespondsToWillUnhide) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* willUnhide = - [NSNotification notificationWithName:NSApplicationWillUnhideNotification object:nil]; - [registrar handleWillUnhide:willUnhide]; - EXPECT_EQ([delegate lastNotification], willUnhide); -} - -TEST(FlutterAppLifecycleDelegateTest, RespondsToDidHide) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* didHide = [NSNotification notificationWithName:NSApplicationDidHideNotification - object:nil]; - [registrar handleDidHide:didHide]; - EXPECT_EQ([delegate lastNotification], didHide); -} - -TEST(FlutterAppLifecycleDelegateTest, RespondsToDidUnhide) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* didUnhide = - [NSNotification notificationWithName:NSApplicationDidUnhideNotification object:nil]; - [registrar handleDidUnhide:didUnhide]; - EXPECT_EQ([delegate lastNotification], didUnhide); -} - -TEST(FlutterAppLifecycleDelegateTest, RespondsToDidChangeScreenParameters) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* didChangeScreenParameters = - [NSNotification notificationWithName:NSApplicationDidChangeScreenParametersNotification - object:nil]; - [registrar handleDidChangeScreenParameters:didChangeScreenParameters]; - EXPECT_EQ([delegate lastNotification], didChangeScreenParameters); -} - -TEST(FlutterAppLifecycleDelegateTest, RespondsToDidChangeOcclusionState) { - FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init]; - TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init]; - [registrar addDelegate:delegate]; - - NSNotification* didChangeOcclusionState = - [NSNotification notificationWithName:NSApplicationDidChangeOcclusionStateNotification - object:nil]; - if ([registrar respondsToSelector:@selector(handleDidChangeOcclusionState:)]) { - [registrar handleDidChangeOcclusionState:didChangeOcclusionState]; - EXPECT_EQ([delegate lastNotification], didChangeOcclusionState); - } -} - -} // namespace flutter::testing diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index 2be2f6b70af8f..d4f194cfca01e 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -9,7 +9,6 @@ #include #include -#include "flutter/shell/platform/common/app_lifecycle_state.h" #include "flutter/shell/platform/common/engine_switches.h" #include "flutter/shell/platform/embedder/embedder.h" @@ -25,8 +24,6 @@ #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.h" NSString* const kFlutterPlatformChannel = @"flutter/platform"; -NSString* const kFlutterSettingsChannel = @"flutter/settings"; -NSString* const kFlutterLifecycleChannel = @"flutter/lifecycle"; /** * Constructs and returns a FlutterLocale struct corresponding to |locale|, which must outlive @@ -176,7 +173,8 @@ - (instancetype)initWithEngine:(FlutterEngine*)engine _terminator = terminator ? terminator : ^(id sender) { // Default to actually terminating the application. The terminator exists to // allow tests to override it so that an actual exit doesn't occur. - [[NSApplication sharedApplication] terminate:sender]; + NSApplication* flutterApp = [NSApplication sharedApplication]; + [flutterApp terminate:sender]; }; FlutterAppDelegate* appDelegate = (FlutterAppDelegate*)[[NSApplication sharedApplication] delegate]; @@ -392,14 +390,7 @@ @implementation FlutterEngine { FlutterThreadSynchronizer* _threadSynchronizer; - // The next available view ID. int _nextViewId; - - // Whether the application is currently the active application. - BOOL _active; - - // Whether any portion of the application is currently visible. - BOOL _visible; } - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)project { @@ -411,8 +402,7 @@ - (instancetype)initWithName:(NSString*)labelPrefix allowHeadlessExecution:(BOOL)allowHeadlessExecution { self = [super init]; NSAssert(self, @"Super init cannot be nil"); - _active = NO; - _visible = NO; + _project = project ?: [[FlutterDartProject alloc] init]; _messengerHandlers = [[NSMutableDictionary alloc] init]; _currentMessengerConnection = 1; @@ -443,19 +433,11 @@ - (instancetype)initWithName:(NSString*)labelPrefix [self setUpPlatformViewChannel]; [self setUpAccessibilityChannel]; [self setUpNotificationCenterListeners]; - FlutterAppDelegate* appDelegate = - reinterpret_cast([[NSApplication sharedApplication] delegate]); - [appDelegate addApplicationLifecycleDelegate:self]; return self; } - (void)dealloc { - FlutterAppDelegate* appDelegate = - reinterpret_cast([[NSApplication sharedApplication] delegate]); - if (appDelegate != nil) { - [appDelegate removeApplicationLifecycleDelegate:self]; - } @synchronized(_isResponseValid) { [_isResponseValid removeAllObjects]; [_isResponseValid addObject:@NO]; @@ -1015,11 +997,11 @@ - (void)addInternalPlugins { [FlutterMouseCursorPlugin registerWithRegistrar:[self registrarForPlugin:@"mousecursor"]]; [FlutterMenuPlugin registerWithRegistrar:[self registrarForPlugin:@"menu"]]; _settingsChannel = - [FlutterBasicMessageChannel messageChannelWithName:kFlutterSettingsChannel + [FlutterBasicMessageChannel messageChannelWithName:@"flutter/settings" binaryMessenger:self.binaryMessenger codec:[FlutterJSONMessageCodec sharedInstance]]; _platformChannel = - [FlutterMethodChannel methodChannelWithName:kFlutterPlatformChannel + [FlutterMethodChannel methodChannelWithName:@"flutter/platform" binaryMessenger:self.binaryMessenger codec:[FlutterJSONMethodCodec sharedInstance]]; [_platformChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { @@ -1077,7 +1059,7 @@ - (void)announceAccessibilityMessage:(NSString*)message } - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { if ([call.method isEqualToString:@"SystemNavigator.pop"]) { - [[NSApplication sharedApplication] terminate:self]; + [NSApp terminate:self]; result(nil); } else if ([call.method isEqualToString:@"SystemSound.play"]) { [self playSystemSound:call.arguments]; @@ -1139,60 +1121,6 @@ - (FlutterThreadSynchronizer*)testThreadSynchronizer { return _threadSynchronizer; } -#pragma mark - FlutterAppLifecycleDelegate - -- (void)setApplicationState:(flutter::AppLifecycleState)state { - NSString* nextState = - [[NSString alloc] initWithCString:flutter::AppLifecycleStateToString(state)]; - [self sendOnChannel:kFlutterLifecycleChannel - message:[nextState dataUsingEncoding:NSUTF8StringEncoding]]; -} - -/** - * Called when the |FlutterAppDelegate| gets the applicationWillBecomeActive - * notification. - */ -- (void)handleWillBecomeActive:(NSNotification*)notification { - _active = YES; - if (!_visible) { - [self setApplicationState:flutter::AppLifecycleState::kHidden]; - } else { - [self setApplicationState:flutter::AppLifecycleState::kResumed]; - } -} - -/** - * Called when the |FlutterAppDelegate| gets the applicationWillResignActive - * notification. - */ -- (void)handleWillResignActive:(NSNotification*)notification { - _active = NO; - if (!_visible) { - [self setApplicationState:flutter::AppLifecycleState::kHidden]; - } else { - [self setApplicationState:flutter::AppLifecycleState::kInactive]; - } -} - -/** - * Called when the |FlutterAppDelegate| gets the applicationDidUnhide - * notification. - */ -- (void)handleDidChangeOcclusionState:(NSNotification*)notification API_AVAILABLE(macos(10.9)) { - NSApplicationOcclusionState occlusionState = [[NSApplication sharedApplication] occlusionState]; - if (occlusionState & NSApplicationOcclusionStateVisible) { - _visible = YES; - if (_active) { - [self setApplicationState:flutter::AppLifecycleState::kResumed]; - } else { - [self setApplicationState:flutter::AppLifecycleState::kInactive]; - } - } else { - _visible = NO; - [self setApplicationState:flutter::AppLifecycleState::kHidden]; - } -} - #pragma mark - FlutterBinaryMessenger - (void)sendOnChannel:(nonnull NSString*)channel message:(nullable NSData*)message { diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm index 60e8bc363f8df..cf81a8ad798c2 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm @@ -805,75 +805,55 @@ - (nonnull NSView*)createWithViewIdentifier:(int64_t)viewId arguments:(nullable EXPECT_TRUE(announced); } -TEST_F(FlutterEngineTest, HandleLifecycleStates) API_AVAILABLE(macos(10.9)) { - __block flutter::AppLifecycleState sentState; - id engineMock = CreateMockFlutterEngine(nil); - - // Have to enumerate all the values because OCMStub can't capture - // non-Objective-C object arguments. - OCMStub([engineMock setApplicationState:flutter::AppLifecycleState::kDetached]) - .andDo((^(NSInvocation* invocation) { - sentState = flutter::AppLifecycleState::kDetached; - })); - OCMStub([engineMock setApplicationState:flutter::AppLifecycleState::kResumed]) - .andDo((^(NSInvocation* invocation) { - sentState = flutter::AppLifecycleState::kResumed; - })); - OCMStub([engineMock setApplicationState:flutter::AppLifecycleState::kInactive]) - .andDo((^(NSInvocation* invocation) { - sentState = flutter::AppLifecycleState::kInactive; - })); - OCMStub([engineMock setApplicationState:flutter::AppLifecycleState::kHidden]) - .andDo((^(NSInvocation* invocation) { - sentState = flutter::AppLifecycleState::kHidden; - })); - OCMStub([engineMock setApplicationState:flutter::AppLifecycleState::kPaused]) - .andDo((^(NSInvocation* invocation) { - sentState = flutter::AppLifecycleState::kPaused; +TEST_F(FlutterEngineTest, RunWithEntrypointUpdatesDisplayConfig) { + BOOL updated = NO; + FlutterEngine* engine = GetFlutterEngine(); + auto original_update_displays = engine.embedderAPI.NotifyDisplayUpdate; + engine.embedderAPI.NotifyDisplayUpdate = MOCK_ENGINE_PROC( + NotifyDisplayUpdate, ([&updated, &original_update_displays]( + auto engine, auto update_type, auto* displays, auto display_count) { + updated = YES; + return original_update_displays(engine, update_type, displays, display_count); })); - __block NSApplicationOcclusionState visibility = NSApplicationOcclusionStateVisible; - id mockApplication = OCMPartialMock([NSApplication sharedApplication]); - OCMStub((NSApplicationOcclusionState)[mockApplication occlusionState]) - .andDo(^(NSInvocation* invocation) { - [invocation setReturnValue:&visibility]; - }); - - NSNotification* willBecomeActive = - [[NSNotification alloc] initWithName:NSApplicationWillBecomeActiveNotification - object:nil - userInfo:nil]; - NSNotification* willResignActive = - [[NSNotification alloc] initWithName:NSApplicationWillResignActiveNotification - object:nil - userInfo:nil]; - - NSNotification* didChangeOcclusionState; - didChangeOcclusionState = - [[NSNotification alloc] initWithName:NSApplicationDidChangeOcclusionStateNotification - object:nil - userInfo:nil]; - - [engineMock handleDidChangeOcclusionState:didChangeOcclusionState]; - EXPECT_EQ(sentState, flutter::AppLifecycleState::kInactive); + EXPECT_TRUE([engine runWithEntrypoint:@"main"]); + EXPECT_TRUE(updated); - [engineMock handleWillBecomeActive:willBecomeActive]; - EXPECT_EQ(sentState, flutter::AppLifecycleState::kResumed); + updated = NO; + [[NSNotificationCenter defaultCenter] + postNotificationName:NSApplicationDidChangeScreenParametersNotification + object:nil]; + EXPECT_TRUE(updated); +} - [engineMock handleWillResignActive:willResignActive]; - EXPECT_EQ(sentState, flutter::AppLifecycleState::kInactive); +TEST_F(FlutterEngineTest, NotificationsUpdateDisplays) { + BOOL updated = NO; + FlutterEngine* engine = GetFlutterEngine(); + auto original_set_viewport_metrics = engine.embedderAPI.SendWindowMetricsEvent; + engine.embedderAPI.SendWindowMetricsEvent = MOCK_ENGINE_PROC( + SendWindowMetricsEvent, + ([&updated, &original_set_viewport_metrics](auto engine, auto* window_metrics) { + updated = YES; + return original_set_viewport_metrics(engine, window_metrics); + })); - visibility = 0; - [engineMock handleDidChangeOcclusionState:didChangeOcclusionState]; - EXPECT_EQ(sentState, flutter::AppLifecycleState::kHidden); + EXPECT_TRUE([engine runWithEntrypoint:@"main"]); - [engineMock handleWillBecomeActive:willBecomeActive]; - EXPECT_EQ(sentState, flutter::AppLifecycleState::kHidden); + updated = NO; + [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowDidChangeScreenNotification + object:nil]; + // No VC. + EXPECT_FALSE(updated); - [engineMock handleWillResignActive:willResignActive]; - EXPECT_EQ(sentState, flutter::AppLifecycleState::kHidden); + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engine + nibName:nil + bundle:nil]; + [viewController loadView]; + viewController.flutterView.frame = CGRectMake(0, 0, 800, 600); - [mockApplication stopMocking]; + [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowDidChangeScreenNotification + object:nil]; + EXPECT_TRUE(updated); } } // namespace flutter::testing diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h index 71fe5481cf72b..be973222ca95d 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h @@ -8,8 +8,6 @@ #include -#include "flutter/shell/platform/common/app_lifecycle_state.h" - #import "flutter/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMac.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h" @@ -174,14 +172,6 @@ typedef NS_ENUM(NSInteger, FlutterAppExitResponse) { - (nonnull FlutterPlatformViewController*)platformViewController; -/** - * Handles changes to the application state, sending them to the framework. - * - * @param state One of the lifecycle constants in app_lifecycle_state.h, - * corresponding to the Dart enum AppLifecycleState. - */ -- (void)setApplicationState:(flutter::AppLifecycleState)state; - // Accessibility API. /** diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 4af1f89fe6bd3..5cb9f2839aaa8 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -158,7 +158,6 @@ source_set("flutter_linux_sources") { ] deps = [ - "//flutter/shell/platform/common:common_cpp_enums", "//flutter/shell/platform/common:common_cpp_input", "//flutter/shell/platform/common:common_cpp_switches", "//flutter/shell/platform/embedder:embedder_headers", @@ -258,7 +257,6 @@ executable("flutter_linux_unittests") { ":flutter_linux_gschemas", ":flutter_linux_sources", "//flutter/runtime:libdart", - "//flutter/shell/platform/common:common_cpp_enums", "//flutter/shell/platform/embedder:embedder_headers", "//flutter/shell/platform/embedder:embedder_test_utils", "//flutter/testing", diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 507d9e2271470..0ae331b328375 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -10,7 +10,6 @@ #include #include -#include "flutter/shell/platform/common/app_lifecycle_state.h" #include "flutter/shell/platform/common/engine_switches.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" @@ -24,7 +23,6 @@ #include "flutter/shell/platform/linux/fl_texture_gl_private.h" #include "flutter/shell/platform/linux/fl_texture_registrar_private.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_string_codec.h" // Unique number associated with platform tasks. static constexpr size_t kPlatformTaskRunnerIdentifier = 1; @@ -34,8 +32,6 @@ static constexpr size_t kPlatformTaskRunnerIdentifier = 1; static constexpr int32_t kMousePointerDeviceId = 0; static constexpr int32_t kPointerPanZoomDeviceId = 1; -static constexpr const char* kFlutterLifecycleChannel = "flutter/lifecycle"; - struct _FlEngine { GObject parent_instance; @@ -126,25 +122,6 @@ static void parse_locale(const gchar* locale, } } -static void set_app_lifecycle_state(FlEngine* self, - const flutter::AppLifecycleState state) { - FlBinaryMessenger* binary_messenger = fl_engine_get_binary_messenger(self); - - g_autoptr(FlValue) value = - fl_value_new_string(flutter::AppLifecycleStateToString(state)); - g_autoptr(FlStringCodec) codec = fl_string_codec_new(); - g_autoptr(GBytes) message = - fl_message_codec_encode_message(FL_MESSAGE_CODEC(codec), value, nullptr); - - if (message == nullptr) { - return; - } - - fl_binary_messenger_send_on_channel(binary_messenger, - kFlutterLifecycleChannel, message, - nullptr, nullptr, nullptr); -} - // Passes locale information to the Flutter engine. static void setup_locales(FlEngine* self) { const gchar* const* languages = g_get_language_names(); @@ -744,18 +721,6 @@ GBytes* fl_engine_send_platform_message_finish(FlEngine* self, return static_cast(g_task_propagate_pointer(G_TASK(result), error)); } -void fl_engine_send_window_state_event(FlEngine* self, - gboolean visible, - gboolean focused) { - if (visible && focused) { - set_app_lifecycle_state(self, flutter::AppLifecycleState::kResumed); - } else if (visible) { - set_app_lifecycle_state(self, flutter::AppLifecycleState::kInactive); - } else { - set_app_lifecycle_state(self, flutter::AppLifecycleState::kHidden); - } -} - void fl_engine_send_window_metrics_event(FlEngine* self, size_t width, size_t height, diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index 4b0227a62750a..0d1dd1c958436 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -167,18 +167,6 @@ void fl_engine_send_window_metrics_event(FlEngine* engine, size_t height, double pixel_ratio); -/** - * fl_engine_send_window_state_event: - * @engine: an #FlEngine. - * @visible: whether the window is currently visible or not. - * @focused: whether the window is currently focused or not. - * - * Sends a window state event to the engine. - */ -void fl_engine_send_window_state_event(FlEngine* engine, - gboolean visible, - gboolean focused); - /** * fl_engine_send_mouse_pointer_event: * @engine: an #FlEngine. diff --git a/shell/platform/linux/fl_engine_test.cc b/shell/platform/linux/fl_engine_test.cc index a7329a6997b0f..a1d6e1d650eaf 100644 --- a/shell/platform/linux/fl_engine_test.cc +++ b/shell/platform/linux/fl_engine_test.cc @@ -5,12 +5,10 @@ // Included first as it collides with the X11 headers. #include "gtest/gtest.h" -#include "flutter/shell/platform/common/app_lifecycle_state.h" #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_string_codec.h" #include "flutter/shell/platform/linux/testing/fl_test.h" // MOCK_ENGINE_PROC is leaky by design @@ -425,42 +423,6 @@ TEST(FlEngineTest, SwitchesEmpty) { EXPECT_EQ(switches->len, 0U); } -TEST(FlEngineTest, SendWindowStateEvent) { - g_autoptr(FlEngine) engine = make_mock_engine(); - FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); - - bool called = false; - std::string state; - embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC( - SendPlatformMessage, - ([&called, &state](auto engine, const FlutterPlatformMessage* message) { - EXPECT_STREQ(message->channel, "flutter/lifecycle"); - called = true; - g_autoptr(FlStringCodec) codec = fl_string_codec_new(); - g_autoptr(GBytes) data = - g_bytes_new(message->message, message->message_size); - g_autoptr(GError) error = nullptr; - g_autoptr(FlValue) parsed_state = fl_message_codec_decode_message( - FL_MESSAGE_CODEC(codec), data, &error); - - state = fl_value_get_string(parsed_state); - return kSuccess; - })); - fl_engine_send_window_state_event(engine, false, false); - EXPECT_STREQ(state.c_str(), flutter::AppLifecycleStateToString( - flutter::AppLifecycleState::kHidden)); - fl_engine_send_window_state_event(engine, false, true); - EXPECT_STREQ(state.c_str(), flutter::AppLifecycleStateToString( - flutter::AppLifecycleState::kHidden)); - fl_engine_send_window_state_event(engine, true, false); - EXPECT_STREQ(state.c_str(), flutter::AppLifecycleStateToString( - flutter::AppLifecycleState::kInactive)); - fl_engine_send_window_state_event(engine, true, true); - EXPECT_STREQ(state.c_str(), flutter::AppLifecycleStateToString( - flutter::AppLifecycleState::kResumed)); - EXPECT_TRUE(called); -} - #ifndef FLUTTER_RELEASE TEST(FlEngineTest, Switches) { g_autoptr(FlEngine) engine = make_mock_engine(); diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 46540d3b60c43..58f11ebf68b10 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -42,9 +42,6 @@ struct _FlView { // Pointer button state recorded for sending status updates. int64_t button_state; - // Current state information for the window associated with this view. - GdkWindowState window_state; - // Flutter system channel handlers. FlAccessibilityPlugin* accessibility_plugin; FlKeyboardManager* keyboard_manager; @@ -62,9 +59,7 @@ struct _FlView { /* FlKeyboardViewDelegate related properties */ KeyboardLayoutNotifier keyboard_layout_notifier; GdkKeymap* keymap; - gulong keymap_keys_changed_cb_id; // Signal connection ID for - // keymap-keys-changed - gulong window_state_cb_id; // Signal connection ID for window-state-changed + gulong keymap_keys_changed_cb_id; // Signal connection ID. }; enum { kPropFlutterProject = 1, kPropLast }; @@ -240,8 +235,6 @@ static void on_pre_engine_restart_cb(FlEngine* engine, gpointer user_data) { g_clear_object(&self->scrolling_manager); init_keyboard(self); init_scrolling(self); - self->window_state = - gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(self))); } // Implements FlPluginRegistry::get_registrar_for_plugin. @@ -487,42 +480,12 @@ static void gesture_zoom_end_cb(GtkGestureZoom* gesture, fl_scrolling_manager_handle_zoom_end(self->scrolling_manager); } -static gboolean window_state_event_cb(GtkWidget* widget, - GdkEvent* event, - gpointer user_data) { - g_return_val_if_fail(FL_IS_VIEW(user_data), FALSE); - g_return_val_if_fail(FL_IS_ENGINE(FL_VIEW(user_data)->engine), FALSE); - FlView* self = FL_VIEW(user_data); - GdkWindowState state = event->window_state.new_window_state; - GdkWindowState previous_state = self->window_state; - self->window_state = state; - bool was_visible = !((previous_state & GDK_WINDOW_STATE_WITHDRAWN) || - (previous_state & GDK_WINDOW_STATE_ICONIFIED)); - bool is_visible = !((state & GDK_WINDOW_STATE_WITHDRAWN) || - (state & GDK_WINDOW_STATE_ICONIFIED)); - bool was_focused = (previous_state & GDK_WINDOW_STATE_FOCUSED); - bool is_focused = (state & GDK_WINDOW_STATE_FOCUSED); - if (was_visible != is_visible || was_focused != is_focused) { - if (self->engine != nullptr) { - fl_engine_send_window_state_event(FL_ENGINE(self->engine), is_visible, - is_focused); - } - } - return FALSE; -} - static void realize_cb(GtkWidget* widget) { FlView* self = FL_VIEW(widget); g_autoptr(GError) error = nullptr; // Handle requests by the user to close the application. GtkWidget* toplevel_window = gtk_widget_get_toplevel(GTK_WIDGET(self)); - - // Listen to window state changes. - self->window_state_cb_id = - g_signal_connect(toplevel_window, "window-state-event", - G_CALLBACK(window_state_event_cb), self); - g_signal_connect(toplevel_window, "delete-event", G_CALLBACK(window_delete_event_cb), self); @@ -661,12 +624,6 @@ static void fl_view_dispose(GObject* object) { nullptr); } - if (self->window_state_cb_id != 0) { - GtkWidget* toplevel_window = gtk_widget_get_toplevel(GTK_WIDGET(self)); - g_signal_handler_disconnect(toplevel_window, self->window_state_cb_id); - self->window_state_cb_id = 0; - } - g_clear_object(&self->project); g_clear_object(&self->renderer); g_clear_object(&self->engine); @@ -726,8 +683,6 @@ static void fl_view_class_init(FlViewClass* klass) { static void fl_view_init(FlView* self) { gtk_widget_set_can_focus(GTK_WIDGET(self), TRUE); - self->window_state = gdk_window_get_state( - gtk_widget_get_window(gtk_widget_get_toplevel(GTK_WIDGET(self)))); } G_MODULE_EXPORT FlView* fl_view_new(FlDartProject* project) { diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 0effa94ed4dc8..db9053a34e453 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -129,7 +129,6 @@ source_set("flutter_windows_source") { public_deps = [ "//flutter/fml:string_conversion", "//flutter/shell/platform/common:common_cpp_accessibility", - "//flutter/shell/platform/common:common_cpp_enums", ] deps = [ diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index c6c46d7301776..8d8f3f15d358d 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -397,7 +397,6 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) { displays.data(), displays.size()); SendSystemLocales(); - SetLifecycleState(flutter::AppLifecycleState::kResumed); settings_plugin_->StartWatching(); settings_plugin_->SendSettings(); @@ -563,13 +562,6 @@ void FlutterWindowsEngine::SetNextFrameCallback(fml::closure callback) { this); } -void FlutterWindowsEngine::SetLifecycleState(flutter::AppLifecycleState state) { - const char* state_name = flutter::AppLifecycleStateToString(state); - SendPlatformMessage("flutter/lifecycle", - reinterpret_cast(state_name), - strlen(state_name), nullptr, nullptr); -} - void FlutterWindowsEngine::SendSystemLocales() { std::vector languages = GetPreferredLanguageInfo(*windows_registry_); diff --git a/shell/platform/windows/flutter_windows_engine.h b/shell/platform/windows/flutter_windows_engine.h index 9fd7df9f4985a..36d21f822df54 100644 --- a/shell/platform/windows/flutter_windows_engine.h +++ b/shell/platform/windows/flutter_windows_engine.h @@ -16,7 +16,6 @@ #include "flutter/fml/closure.h" #include "flutter/fml/macros.h" #include "flutter/shell/platform/common/accessibility_bridge.h" -#include "flutter/shell/platform/common/app_lifecycle_state.h" #include "flutter/shell/platform/common/client_wrapper/binary_messenger_impl.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/basic_message_channel.h" #include "flutter/shell/platform/common/incoming_message_dispatcher.h" @@ -307,9 +306,6 @@ class FlutterWindowsEngine { // system changes. void SendSystemLocales(); - // Sends the current lifecycle state to the framework. - void SetLifecycleState(flutter::AppLifecycleState state); - // Create the keyboard & text input sub-systems. // // This requires that a view is attached to the engine. diff --git a/tools/api_check/test/apicheck_test.dart b/tools/api_check/test/apicheck_test.dart index f32bb339f8f8a..22dea01379613 100644 --- a/tools/api_check/test/apicheck_test.dart +++ b/tools/api_check/test/apicheck_test.dart @@ -43,6 +43,10 @@ void checkApiConsistency(String flutterRoot) { sourcePath: path.join(flutterRoot, 'lib', 'ui', 'window.dart'), className: 'AccessibilityFeatures', ); + final List webuiFields = getDartClassFields( + sourcePath: path.join(flutterRoot, 'lib', 'ui', 'window.dart'), + className: 'AccessibilityFeatures', + ); // C values: kFlutterAccessibilityFeatureFooBar = 1 << N, final List embedderEnumValues = getCppEnumValues( sourcePath: path.join(flutterRoot, 'shell', 'platform', 'embedder', 'embedder.h'), @@ -60,6 +64,7 @@ void checkApiConsistency(String flutterRoot) { enumName: 'AccessibilityFeature', ).map(allCapsToCamelCase).toList(); + expect(webuiFields, uiFields); expect(embedderEnumValues, uiFields); expect(internalEnumValues, uiFields); expect(javaEnumValues, uiFields); @@ -72,7 +77,7 @@ void checkApiConsistency(String flutterRoot) { className: 'SemanticsAction', ); final List webuiFields = getDartClassFields( - sourcePath: path.join(flutterRoot, 'lib', 'web_ui', 'lib', 'semantics.dart'), + sourcePath: path.join(flutterRoot, 'lib', 'ui', 'semantics.dart'), className: 'SemanticsAction', ); // C values: kFlutterSemanticsActionFooBar = 1 << N. @@ -98,33 +103,6 @@ void checkApiConsistency(String flutterRoot) { expect(javaEnumValues, uiFields); }); - test('AppLifecycleState enums match', () { - // Dart values: _kFooBarIndex = 1 << N. - final List uiFields = getDartClassFields( - sourcePath: path.join(flutterRoot, 'lib', 'ui', 'platform_dispatcher.dart'), - className: 'AppLifecycleState', - ); - final List webuiFields = getDartClassFields( - sourcePath: path.join(flutterRoot, 'lib', 'web_ui', 'lib', 'platform_dispatcher.dart'), - className: 'AppLifecycleState', - ); - // C++ values: kFooBar = 1 << N. - final List internalEnumValues = getCppEnumClassValues( - sourcePath: path.join(flutterRoot, 'shell', 'platform', 'common', 'app_lifecycle_state.h'), - enumName: 'AppLifecycleState', - ); - // Java values: FOO_BAR(1 << N). - final List javaEnumValues = getJavaEnumValues( - sourcePath: path.join(flutterRoot, 'shell', 'platform', 'android', 'io', - 'flutter', 'embedding', 'engine', 'systemchannels', 'LifecycleChannel.java'), - enumName: 'AppLifecycleState', - ).map(allCapsToCamelCase).toList(); - - expect(webuiFields, uiFields); - expect(internalEnumValues, uiFields); - expect(javaEnumValues, uiFields); - }); - test('SemanticsFlag enums match', () { // Dart values: _kFooBarIndex = 1 << N. final List uiFields = getDartClassFields(