diff --git a/shell/platform/tizen/BUILD.gn b/shell/platform/tizen/BUILD.gn index bd33143429e3a..5c67ed8e217b8 100644 --- a/shell/platform/tizen/BUILD.gn +++ b/shell/platform/tizen/BUILD.gn @@ -32,6 +32,7 @@ _flutter_tizen_source = [ "channels/navigation_channel.cc", "channels/platform_view_channel.cc", "channels/text_input_channel.cc", + "flutter_project_bundle.cc", "flutter_tizen.cc", "flutter_tizen_engine.cc", "flutter_tizen_texture_registrar.cc", @@ -139,6 +140,7 @@ template("embedder_for_profile") { libs += [ "base-utils-i18n", "capi-appfw-application", + "capi-appfw-app-common", "capi-base-common", "capi-system-info", "capi-system-system-settings", diff --git a/shell/platform/tizen/external_texture.h b/shell/platform/tizen/external_texture.h index de5e416a3fa36..281a055703dc9 100644 --- a/shell/platform/tizen/external_texture.h +++ b/shell/platform/tizen/external_texture.h @@ -7,6 +7,7 @@ #include #include + #include "flutter/shell/platform/common/public/flutter_texture_registrar.h" #include "flutter/shell/platform/embedder/embedder.h" diff --git a/shell/platform/tizen/flutter_project_bundle.cc b/shell/platform/tizen/flutter_project_bundle.cc new file mode 100644 index 0000000000000..b36ec06fcd488 --- /dev/null +++ b/shell/platform/tizen/flutter_project_bundle.cc @@ -0,0 +1,101 @@ +// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved. +// 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. + +#include "flutter_project_bundle.h" + +#ifdef __X64_SHELL__ +#include "flutter/shell/platform/common/path_utils.h" +#else +#include +#endif + +#include + +#include "flutter/shell/platform/tizen/tizen_log.h" + +namespace flutter { + +#ifndef __X64_SHELL__ +namespace { + +// Returns the path of the directory containing the app binary, or an empty +// string if the directory cannot be found. +std::filesystem::path GetExecutableDirectory() { + auto res_path = app_get_resource_path(); + if (res_path == nullptr) { + return std::filesystem::path(); + } + auto bin_path = std::filesystem::path(res_path) / ".." / "bin"; + free(res_path); + return bin_path.lexically_normal(); +} + +} // namespace +#endif + +FlutterProjectBundle::FlutterProjectBundle( + const FlutterDesktopEngineProperties& properties) + : assets_path_(properties.assets_path), + icu_path_(properties.icu_data_path) { + if (properties.aot_library_path != nullptr) { + aot_library_path_ = std::filesystem::path(properties.aot_library_path); + } + + // Resolve any relative paths. + if (assets_path_.is_relative() || icu_path_.is_relative() || + (!aot_library_path_.empty() && aot_library_path_.is_relative())) { + std::filesystem::path executable_location = GetExecutableDirectory(); + if (executable_location.empty()) { + FT_LOGE("Unable to find executable location to resolve resource paths."); + assets_path_ = std::filesystem::path(); + icu_path_ = std::filesystem::path(); + } else { + assets_path_ = std::filesystem::path(executable_location) / assets_path_; + icu_path_ = std::filesystem::path(executable_location) / icu_path_; + if (!aot_library_path_.empty()) { + aot_library_path_ = + std::filesystem::path(executable_location) / aot_library_path_; + } + } + } + + switches_.insert(switches_.end(), properties.switches, + properties.switches + properties.switches_count); +} + +bool FlutterProjectBundle::HasValidPaths() { + return !assets_path_.empty() && !icu_path_.empty(); +} + +// Attempts to load AOT data from the given path, which must be absolute and +// non-empty. Logs and returns nullptr on failure. +UniqueAotDataPtr FlutterProjectBundle::LoadAotData( + const FlutterEngineProcTable& engine_procs) { + if (aot_library_path_.empty()) { + FT_LOGE( + "Attempted to load AOT data, but no aot_library_path was provided."); + return UniqueAotDataPtr(nullptr, nullptr); + } + if (!std::filesystem::exists(aot_library_path_)) { + FT_LOGE("Can't load AOT data from %s; no such file.", + aot_library_path_.u8string().c_str()); + return UniqueAotDataPtr(nullptr, nullptr); + } + std::string path_string = aot_library_path_.u8string(); + FlutterEngineAOTDataSource source = {}; + source.type = kFlutterEngineAOTDataSourceTypeElfPath; + source.elf_path = path_string.c_str(); + FlutterEngineAOTData data = nullptr; + auto result = engine_procs.CreateAOTData(&source, &data); + if (result != kSuccess) { + FT_LOGE("Failed to load AOT data from: %s", path_string.c_str()); + return UniqueAotDataPtr(nullptr, nullptr); + } + return UniqueAotDataPtr(data, engine_procs.CollectAOTData); +} + +FlutterProjectBundle::~FlutterProjectBundle() {} + +} // namespace flutter diff --git a/shell/platform/tizen/flutter_project_bundle.h b/shell/platform/tizen/flutter_project_bundle.h new file mode 100644 index 0000000000000..bf0f24fdc51b6 --- /dev/null +++ b/shell/platform/tizen/flutter_project_bundle.h @@ -0,0 +1,62 @@ +// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved. +// 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 EMBEDDER_FLUTTER_PROJECT_BUNDLE_H_ +#define EMBEDDER_FLUTTER_PROJECT_BUNDLE_H_ + +#include +#include +#include + +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/tizen/public/flutter_tizen.h" + +namespace flutter { + +using UniqueAotDataPtr = + std::unique_ptr<_FlutterEngineAOTData, FlutterEngineCollectAOTDataFnPtr>; + +// The data associated with a Flutter project needed to run it in an engine. +class FlutterProjectBundle { + public: + // Creates a new project bundle from the given properties. + // + // Treats any relative paths as relative to the directory of the app binary. + explicit FlutterProjectBundle( + const FlutterDesktopEngineProperties& properties); + + ~FlutterProjectBundle(); + + // Whether or not the bundle is valid. This does not check that the paths + // exist, or contain valid data, just that paths were able to be constructed. + bool HasValidPaths(); + + // Returns the path to the assets directory. + const std::filesystem::path& assets_path() { return assets_path_; } + + // Returns the path to the ICU data file. + const std::filesystem::path& icu_path() { return icu_path_; } + + // Returns any switches that should be passed to the engine. + const std::vector switches() { return switches_; } + + // Attempts to load AOT data for this bundle. The returned data must be + // retained until any engine instance it is passed to has been shut down. + // + // Logs and returns nullptr on failure. + UniqueAotDataPtr LoadAotData(const FlutterEngineProcTable& engine_procs); + + private: + std::filesystem::path assets_path_; + std::filesystem::path icu_path_; + std::vector switches_ = {}; + + // Path to the AOT library file, if any. + std::filesystem::path aot_library_path_; +}; + +} // namespace flutter + +#endif // EMBEDDER_FLUTTER_PROJECT_BUNDLE_H_ diff --git a/shell/platform/tizen/flutter_tizen.cc b/shell/platform/tizen/flutter_tizen.cc index b588eef534d33..bfb29faa2a32c 100644 --- a/shell/platform/tizen/flutter_tizen.cc +++ b/shell/platform/tizen/flutter_tizen.cc @@ -8,6 +8,7 @@ #include "flutter/shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_message_codec.h" #include "flutter/shell/platform/common/incoming_message_dispatcher.h" +#include "flutter/shell/platform/tizen/flutter_project_bundle.h" #include "flutter/shell/platform/tizen/flutter_tizen_engine.h" #include "flutter/shell/platform/tizen/public/flutter_platform_view.h" #include "flutter/shell/platform/tizen/tizen_log.h" @@ -25,12 +26,18 @@ static FlutterDesktopEngineRef HandleForEngine( } FlutterDesktopEngineRef FlutterDesktopRunEngine( - const FlutterDesktopEngineProperties& engine_properties, - bool headed) { + const FlutterDesktopWindowProperties& window_properties, + const FlutterDesktopEngineProperties& engine_properties) { flutter::StartLogging(); - auto engine = std::make_unique(headed); - if (!engine->RunEngine(engine_properties)) { + flutter::FlutterProjectBundle project(engine_properties); + auto engine = std::make_unique(project); + if (window_properties.headed) { + engine->InitializeRenderer(window_properties.x, window_properties.y, + window_properties.width, + window_properties.height); + } + if (!engine->RunEngine()) { FT_LOGE("Failed to run the Flutter engine."); return nullptr; } diff --git a/shell/platform/tizen/flutter_tizen_engine.cc b/shell/platform/tizen/flutter_tizen_engine.cc index 33f4a3a2f74ad..d9ec11022c1f3 100644 --- a/shell/platform/tizen/flutter_tizen_engine.cc +++ b/shell/platform/tizen/flutter_tizen_engine.cc @@ -5,7 +5,7 @@ #include "flutter_tizen_engine.h" -#include +#include #include #include @@ -33,7 +33,9 @@ constexpr double kProfileFactor = 1.0; } // namespace -FlutterTizenEngine::FlutterTizenEngine(bool headed) { +FlutterTizenEngine::FlutterTizenEngine(const FlutterProjectBundle& project) + : project_(std::make_unique(project)), + aot_data_(nullptr, nullptr) { embedder_api_.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&embedder_api_); @@ -55,19 +57,20 @@ FlutterTizenEngine::FlutterTizenEngine(bool headed) { plugin_registrar_ = std::make_unique(); plugin_registrar_->engine = this; - - if (headed) { - InitializeRenderer(); - } } FlutterTizenEngine::~FlutterTizenEngine() { renderer = nullptr; } -void FlutterTizenEngine::InitializeRenderer() { +void FlutterTizenEngine::InitializeRenderer(int32_t x, + int32_t y, + int32_t width, + int32_t height) { + TizenRenderer::WindowGeometry geometry = {x, y, width, height}; + #ifdef TIZEN_RENDERER_EVAS_GL - renderer = std::make_unique(*this); + renderer = std::make_unique(geometry, *this); render_loop_ = std::make_unique( std::this_thread::get_id(), // main thread @@ -78,7 +81,7 @@ void FlutterTizenEngine::InitializeRenderer() { }, renderer.get()); #else - renderer = std::make_unique(*this); + renderer = std::make_unique(geometry, *this); tizen_vsync_waiter_ = std::make_unique(this); #endif @@ -88,52 +91,42 @@ void FlutterTizenEngine::NotifyLowMemoryWarning() { embedder_api_.NotifyLowMemoryWarning(engine_); } -// Attempts to load AOT data from the given path, which must be absolute and -// non-empty. Logs and returns nullptr on failure. -UniqueAotDataPtr FlutterTizenEngine::LoadAotData(std::string aot_data_path) { - if (aot_data_path.empty()) { - FT_LOGE( - "Attempted to load AOT data, but no aot_library_path was provided."); - return nullptr; - } - if (!std::filesystem::exists(aot_data_path)) { - FT_LOGE("Can't load AOT data from %s; no such file.", - aot_data_path.c_str()); - return nullptr; - } - FlutterEngineAOTDataSource source = {}; - source.type = kFlutterEngineAOTDataSourceTypeElfPath; - source.elf_path = aot_data_path.c_str(); - FlutterEngineAOTData data = nullptr; - auto result = embedder_api_.CreateAOTData(&source, &data); - if (result != kSuccess) { - FT_LOGE("Failed to load AOT data from: %s", aot_data_path.c_str()); - return nullptr; +bool FlutterTizenEngine::RunEngine() { + if (engine_ != nullptr) { + FT_LOGE("The engine has already started."); + return false; } - return UniqueAotDataPtr(data); -} - -bool FlutterTizenEngine::RunEngine( - const FlutterDesktopEngineProperties& engine_properties) { if (IsHeaded() && !renderer->IsValid()) { FT_LOGE("The display was not valid."); return false; } + if (!project_->HasValidPaths()) { + FT_LOGE("Missing or unresolvable paths to assets."); + return false; + } + std::string assets_path_string = project_->assets_path().u8string(); + std::string icu_path_string = project_->icu_path().u8string(); + if (embedder_api_.RunsAOTCompiledDartCode()) { + aot_data_ = project_->LoadAotData(embedder_api_); + if (!aot_data_) { + FT_LOGE("Unable to start engine without AOT data."); + return false; + } + } + // FlutterProjectArgs is expecting a full argv, so when processing it for // flags the first item is treated as the executable and ignored. Add a dummy // value so that all provided arguments are used. + std::vector switches = project_->switches(); std::vector argv = {"placeholder"}; - if (engine_properties.switches_count > 0) { - argv.insert(argv.end(), &engine_properties.switches[0], - &engine_properties.switches[engine_properties.switches_count]); - } + std::transform( + switches.begin(), switches.end(), std::back_inserter(argv), + [](const std::string& arg) -> const char* { return arg.c_str(); }); - for (size_t i = 0; i < engine_properties.switches_count; ++i) { - auto str = std::string{engine_properties.switches[i]}; - if (str.find("verbose-logging") != std::string::npos) { - SetMinLoggingLevel(DLOG_INFO); - } + if (std::find(switches.begin(), switches.end(), "verbose-logging") != + switches.end()) { + SetMinLoggingLevel(DLOG_INFO); } // Configure task runners. @@ -173,10 +166,10 @@ bool FlutterTizenEngine::RunEngine( FlutterProjectArgs args = {}; args.struct_size = sizeof(FlutterProjectArgs); - args.assets_path = engine_properties.assets_path; - args.icu_data_path = engine_properties.icu_data_path; + args.assets_path = assets_path_string.c_str(); + args.icu_data_path = icu_path_string.c_str(); args.command_line_argc = static_cast(argv.size()); - args.command_line_argv = &argv[0]; + args.command_line_argv = argv.size() > 0 ? argv.data() : nullptr; args.platform_message_callback = [](const FlutterPlatformMessage* engine_message, void* user_data) { if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) { @@ -198,13 +191,7 @@ bool FlutterTizenEngine::RunEngine( }; } #endif - - if (embedder_api_.RunsAOTCompiledDartCode()) { - aot_data_ = LoadAotData(engine_properties.aot_library_path); - if (!aot_data_) { - FT_LOGE("Unable to start engine without AOT data."); - return false; - } + if (aot_data_) { args.aot_data = aot_data_.get(); } @@ -357,7 +344,7 @@ void FlutterTizenEngine::SetWindowOrientation(int32_t degree) { renderer->SetRotate(degree); // Compute renderer transformation based on the angle of rotation. double rad = (360 - degree) * M_PI / 180; - auto geometry = renderer->GetGeometry(); + auto geometry = renderer->GetCurrentGeometry(); double width = geometry.w; double height = geometry.h; diff --git a/shell/platform/tizen/flutter_tizen_engine.h b/shell/platform/tizen/flutter_tizen_engine.h index 882cf931c0355..4586d071b59d9 100644 --- a/shell/platform/tizen/flutter_tizen_engine.h +++ b/shell/platform/tizen/flutter_tizen_engine.h @@ -6,7 +6,6 @@ #ifndef EMBEDDER_FLUTTER_TIZEN_ENGINE_H_ #define EMBEDDER_FLUTTER_TIZEN_ENGINE_H_ -#include #include #include "flutter/shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h" @@ -20,6 +19,7 @@ #include "flutter/shell/platform/tizen/channels/platform_view_channel.h" #include "flutter/shell/platform/tizen/channels/settings_channel.h" #include "flutter/shell/platform/tizen/channels/text_input_channel.h" +#include "flutter/shell/platform/tizen/flutter_project_bundle.h" #include "flutter/shell/platform/tizen/flutter_tizen_texture_registrar.h" #include "flutter/shell/platform/tizen/key_event_handler.h" #include "flutter/shell/platform/tizen/public/flutter_tizen.h" @@ -47,27 +47,25 @@ struct FlutterDesktopMessenger { namespace flutter { -// Custom deleter for FlutterEngineAOTData. -struct AOTDataDeleter { - void operator()(FlutterEngineAOTData aot_data) { - FlutterEngineCollectAOTData(aot_data); - } -}; - -using UniqueAotDataPtr = std::unique_ptr<_FlutterEngineAOTData, AOTDataDeleter>; - // Manages state associated with the underlying FlutterEngine. class FlutterTizenEngine : public TizenRenderer::Delegate { public: - explicit FlutterTizenEngine(bool headed); + // Creates a new Flutter engine object configured to run |project|. + explicit FlutterTizenEngine(const FlutterProjectBundle& project); + virtual ~FlutterTizenEngine(); // Prevent copying. FlutterTizenEngine(FlutterTizenEngine const&) = delete; FlutterTizenEngine& operator=(FlutterTizenEngine const&) = delete; - void InitializeRenderer(); - bool RunEngine(const FlutterDesktopEngineProperties& engine_properties); + // Sets up an instance of TizenRenderer. + void InitializeRenderer(int32_t x, int32_t y, int32_t width, int32_t height); + + // Starts running the engine. + bool RunEngine(); + + // Stops the engine. bool StopEngine(); // Returns the currently configured Plugin Registrar. @@ -139,16 +137,29 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { std::unique_ptr platform_view_channel; private: + // Whether the engine is running in headed or headless mode. bool IsHeaded() { return renderer != nullptr; } - UniqueAotDataPtr LoadAotData(std::string aot_data_path); + FlutterDesktopMessage ConvertToDesktopMessage( const FlutterPlatformMessage& engine_message); + + // Creates and returns a FlutterRendererConfig depending on the current + // display mode (headed or headless). + // The user_data received by the render callbacks refers to the + // FlutterTizenEngine. FlutterRendererConfig GetRendererConfig(); + // The Flutter engine instance. + FLUTTER_API_SYMBOL(FlutterEngine) engine_ = nullptr; + + // The proc table of the embedder APIs. FlutterEngineProcTable embedder_api_ = {}; - // The Flutter engine instance. - FLUTTER_API_SYMBOL(FlutterEngine) engine_; + // The data required for configuring a Flutter engine instance. + std::unique_ptr project_; + + // AOT data for this engine instance, if applicable. + UniqueAotDataPtr aot_data_; // The handlers listening to platform events. std::unique_ptr key_event_handler_; @@ -180,9 +191,6 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { std::unique_ptr tizen_vsync_waiter_; #endif - // AOT data for this engine instance, if applicable. - UniqueAotDataPtr aot_data_; - // The current renderer transformation. FlutterTransformation transformation_; }; diff --git a/shell/platform/tizen/flutter_tizen_engine_unittest.cc b/shell/platform/tizen/flutter_tizen_engine_unittest.cc index 4acce271181b7..a36ab6303cfdd 100644 --- a/shell/platform/tizen/flutter_tizen_engine_unittest.cc +++ b/shell/platform/tizen/flutter_tizen_engine_unittest.cc @@ -1,5 +1,4 @@ -// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved. -// Copyright 2013 The Flutter Authors. All rights reserved. +// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,52 +8,22 @@ namespace flutter { namespace testing { -class FlutterTizenEngineTestSimple : public ::testing::Test { - protected: - void SetUp() { ecore_init(); } -}; - -TEST_F(FlutterTizenEngineTestSimple, Create_Headless) { - flutter::FlutterTizenEngine* tizen_engine = - new flutter::FlutterTizenEngine(false); - EXPECT_TRUE(tizen_engine != nullptr); - delete tizen_engine; -} - -// TODO -TEST_F(FlutterTizenEngineTestSimple, DISABLED_Create_Headed) { - flutter::FlutterTizenEngine* tizen_engine = - new flutter::FlutterTizenEngine(true); - EXPECT_TRUE(tizen_engine != nullptr); - delete tizen_engine; -} - class FlutterTizenEngineTest : public ::testing::Test { public: FlutterTizenEngineTest() { ecore_init(); - - std::string tpk_root; - char path[256]; - EXPECT_TRUE(getcwd(path, sizeof(path)) != NULL); - tpk_root = path + std::string("/tpkroot"); - - assets_path_ = tpk_root + "/res/flutter_assets"; - icu_data_path_ = tpk_root + "/res/icudtl.dat"; - aot_lib_path_ = tpk_root + "/lib/libapp.so"; - - switches_.push_back("--disable-observatory"); + elm_init(0, nullptr); } protected: void SetUp() { - engine_prop_.assets_path = assets_path_.c_str(); - engine_prop_.icu_data_path = icu_data_path_.c_str(); - engine_prop_.aot_library_path = aot_lib_path_.c_str(); - engine_prop_.switches = switches_.data(); - engine_prop_.switches_count = switches_.size(); + FlutterDesktopEngineProperties engine_prop = {}; + engine_prop.assets_path = "foo/flutter_assets"; + engine_prop.icu_data_path = "foo/icudtl.dat"; + engine_prop.aot_library_path = "foo/libapp.so"; - auto engine = std::make_unique(false); + FlutterProjectBundle project(engine_prop); + auto engine = std::make_unique(project); engine_ = engine.release(); } @@ -65,49 +34,50 @@ class FlutterTizenEngineTest : public ::testing::Test { engine_ = nullptr; } - std::string assets_path_; - std::string icu_data_path_; - std::string aot_lib_path_; - flutter::FlutterTizenEngine* engine_; - FlutterDesktopEngineProperties engine_prop_ = {}; - std::vector switches_; + FlutterTizenEngine* engine_; +}; + +class FlutterTizenEngineTestHeaded : public FlutterTizenEngineTest { + protected: + void SetUp() { + FlutterTizenEngineTest::SetUp(); + engine_->InitializeRenderer(0, 0, 800, 600); + } }; TEST_F(FlutterTizenEngineTest, Run) { EXPECT_TRUE(engine_ != nullptr); - EXPECT_TRUE(engine_->RunEngine(engine_prop_)); - EXPECT_TRUE(true); + EXPECT_TRUE(engine_->RunEngine()); } -// TODO -TEST_F(FlutterTizenEngineTest, DISABLED_Run_Twice) { - EXPECT_TRUE(engine_ != nullptr); - EXPECT_TRUE(engine_->RunEngine(engine_prop_)); - EXPECT_FALSE(engine_->RunEngine(engine_prop_)); - EXPECT_TRUE(true); +TEST_F(FlutterTizenEngineTest, Run_Twice) { + EXPECT_TRUE(engine_->RunEngine()); + EXPECT_FALSE(engine_->RunEngine()); } TEST_F(FlutterTizenEngineTest, Stop) { - EXPECT_TRUE(engine_ != nullptr); - EXPECT_TRUE(engine_->RunEngine(engine_prop_)); + EXPECT_TRUE(engine_->RunEngine()); EXPECT_TRUE(engine_->StopEngine()); } TEST_F(FlutterTizenEngineTest, Stop_Twice) { - EXPECT_TRUE(engine_ != nullptr); - EXPECT_TRUE(engine_->RunEngine(engine_prop_)); + EXPECT_TRUE(engine_->RunEngine()); EXPECT_TRUE(engine_->StopEngine()); EXPECT_FALSE(engine_->StopEngine()); } TEST_F(FlutterTizenEngineTest, GetPluginRegistrar) { - EXPECT_TRUE(engine_ != nullptr); + EXPECT_TRUE(engine_->RunEngine()); EXPECT_TRUE(engine_->GetPluginRegistrar() != nullptr); } -// TODO -TEST_F(FlutterTizenEngineTest, DISABLED_GetTextureRegistrar) { - EXPECT_TRUE(engine_ != nullptr); +TEST_F(FlutterTizenEngineTest, GetTextureRegistrar) { + EXPECT_TRUE(engine_->RunEngine()); + EXPECT_TRUE(engine_->GetTextureRegistrar() == nullptr); +} + +TEST_F(FlutterTizenEngineTestHeaded, GetTextureRegistrar) { + EXPECT_TRUE(engine_->RunEngine()); EXPECT_TRUE(engine_->GetTextureRegistrar() != nullptr); } diff --git a/shell/platform/tizen/flutter_tizen_shell.cc b/shell/platform/tizen/flutter_tizen_shell.cc index 1c6749b3439c3..74a740c38785a 100644 --- a/shell/platform/tizen/flutter_tizen_shell.cc +++ b/shell/platform/tizen/flutter_tizen_shell.cc @@ -1,19 +1,15 @@ -#include +// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + #include -#include -#include -#include + +#include +#include #include "flutter/shell/platform/tizen/flutter_tizen_engine.h" #include "flutter/shell/platform/tizen/public/flutter_tizen.h" -extern int gApp_width; -extern int gApp_height; - -std::string TPK_ROOT_PATH = "/tpkroot"; -std::string LIB_PATH = "/lib"; -std::string RES_PATH = "/res"; - class FlutterApp { public: explicit FlutterApp() {} @@ -21,47 +17,42 @@ class FlutterApp { bool OnCreate() { printf("Launching a Flutter application...\n"); - std::string assets_path; - std::string icu_data_path; - std::string aot_lib_path; - FlutterDesktopEngineProperties engine_prop = {}; - std::vector switches; - std::string tpk_root; - if (app_path_.empty()) { - char path[256]; - getcwd(path, sizeof(path)); - tpk_root = path + std::string("/tpkroot"); - } else { - tpk_root = app_path_; - } + FlutterDesktopWindowProperties window_prop = {}; + window_prop.headed = true; + window_prop.x = 0; + window_prop.y = 0; + window_prop.width = window_width_; + window_prop.height = window_height_; - assets_path = tpk_root + "/res/flutter_assets"; - icu_data_path = tpk_root + "/res/icudtl.dat"; - aot_lib_path = tpk_root + "/lib/libapp.so"; + std::string assets_path = app_path_ + "/res/flutter_assets"; + std::string icu_data_path = app_path_ + "/res/icudtl.dat"; + std::string aot_lib_path = app_path_ + "/lib/libapp.so"; + std::vector switches; switches.push_back("--disable-observatory"); switches.push_back("--verbose-logging"); switches.push_back("--enable-dart-profiling"); switches.push_back("--enable-checked-mode"); + FlutterDesktopEngineProperties engine_prop = {}; engine_prop.assets_path = assets_path.c_str(); engine_prop.icu_data_path = icu_data_path.c_str(); engine_prop.aot_library_path = aot_lib_path.c_str(); engine_prop.switches = switches.data(); engine_prop.switches_count = switches.size(); - engine_ = FlutterDesktopRunEngine(engine_prop, true); + engine_ = FlutterDesktopRunEngine(window_prop, engine_prop); if (!engine_) { printf("Could not launch a Flutter application.\n"); return false; } - // RegisterPlugins(this); + return true; } void OnTerminate() { - printf("Shutting down the application..."); + printf("Shutting down the application...\n"); FlutterDesktopShutdownEngine(engine_); engine_ = nullptr; @@ -71,20 +62,26 @@ class FlutterApp { int Run(int argc, char** argv) { ecore_init(); - elm_init(0, 0); + elm_init(0, nullptr); elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); elm_config_accel_preference_set("opengl"); for (int i = 1; i < argc; i++) { if (strstr(argv[i], "--width=") == argv[i]) { - gApp_width = std::atoi(argv[i] + strlen("--width=")); + window_width_ = std::atoi(argv[i] + strlen("--width=")); } else if (strstr(argv[i], "--height=") == argv[i]) { - gApp_height = std::atoi(argv[i] + strlen("--height=")); + window_height_ = std::atoi(argv[i] + strlen("--height=")); } else if (strstr(argv[i], "--tpkroot=") == argv[i]) { app_path_ = argv[i] + strlen("--tpkroot="); } } + if (app_path_.empty()) { + char path[256]; + getcwd(path, sizeof(path)); + app_path_ = path + std::string("/tpkroot"); + } + ecore_idler_add( [](void* data) -> Eina_Bool { FlutterApp* app = (FlutterApp*)data; @@ -94,6 +91,7 @@ class FlutterApp { this); ecore_main_loop_begin(); OnTerminate(); + return 0; } @@ -107,6 +105,9 @@ class FlutterApp { private: std::string app_path_ = {}; + int32_t window_width_ = 0; + int32_t window_height_ = 0; + FlutterDesktopEngineRef engine_ = nullptr; }; diff --git a/shell/platform/tizen/public/flutter_tizen.h b/shell/platform/tizen/public/flutter_tizen.h index deea81d764e37..9cb2da2afb8d0 100644 --- a/shell/platform/tizen/public/flutter_tizen.h +++ b/shell/platform/tizen/public/flutter_tizen.h @@ -21,6 +21,21 @@ extern "C" { struct FlutterDesktopEngine; typedef struct FlutterDesktopEngine* FlutterDesktopEngineRef; +// Properties for configuring the initial settings of a Flutter window. +typedef struct { + // Whether the app is headed or headless. Other properties are ignored if + // this value is set to false. + bool headed; + // The x-coordinate of the top left corner of the window. + int32_t x; + // The y-coordinate of the top left corner of the window. + int32_t y; + // The width of the window, or the maximum width if the value is zero. + int32_t width; + // The height of the window, or the maximum height if the value is zero. + int32_t height; +} FlutterDesktopWindowProperties; + // Properties for configuring a Flutter engine instance. typedef struct { // The path to the flutter_assets folder for the application to be run. @@ -41,9 +56,9 @@ typedef struct { // Runs an instance of a Flutter engine with the given properties. // // If |headed| is false, the engine is run in headless mode. -FLUTTER_EXPORT FlutterDesktopEngineRef -FlutterDesktopRunEngine(const FlutterDesktopEngineProperties& engine_properties, - bool headed); +FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopRunEngine( + const FlutterDesktopWindowProperties& window_properties, + const FlutterDesktopEngineProperties& engine_properties); // Shuts down the given engine instance. // @@ -62,21 +77,29 @@ FlutterDesktopGetPluginRegistrar(FlutterDesktopEngineRef engine, FLUTTER_EXPORT FlutterDesktopMessengerRef FlutterDesktopEngineGetMessenger(FlutterDesktopEngineRef engine); +// Posts a locale change notification to the engine instance. FLUTTER_EXPORT void FlutterDesktopNotifyLocaleChange( FlutterDesktopEngineRef engine); +// Posts a low memory notification to the engine instance. FLUTTER_EXPORT void FlutterDesktopNotifyLowMemoryWarning( FlutterDesktopEngineRef engine); +// Notifies the engine that the app is in an inactive state and not receiving +// user input. FLUTTER_EXPORT void FlutterDesktopNotifyAppIsInactive( FlutterDesktopEngineRef engine); +// Notifies the engine that the app is visible and responding to user input. FLUTTER_EXPORT void FlutterDesktopNotifyAppIsResumed( FlutterDesktopEngineRef engine); +// Notifies the engine that the app is not currently visible to the user, not +// responding to user input, and running in the background. FLUTTER_EXPORT void FlutterDesktopNotifyAppIsPaused( FlutterDesktopEngineRef engine); +// Notifies the engine that the engine is detached from any host views. FLUTTER_EXPORT void FlutterDesktopNotifyAppIsDetached( FlutterDesktopEngineRef engine); diff --git a/shell/platform/tizen/tizen_renderer.cc b/shell/platform/tizen/tizen_renderer.cc index e792904793b15..3692064108500 100644 --- a/shell/platform/tizen/tizen_renderer.cc +++ b/shell/platform/tizen/tizen_renderer.cc @@ -6,8 +6,8 @@ namespace flutter { -TizenRenderer::TizenRenderer(TizenRenderer::Delegate& delegate) - : delegate_(delegate) {} +TizenRenderer::TizenRenderer(WindowGeometry geometry, Delegate& delegate) + : initial_geometry_(geometry), delegate_(delegate) {} TizenRenderer::~TizenRenderer() = default; diff --git a/shell/platform/tizen/tizen_renderer.h b/shell/platform/tizen/tizen_renderer.h index 9d5dfadcd4ecd..f9b793cb8f37f 100644 --- a/shell/platform/tizen/tizen_renderer.h +++ b/shell/platform/tizen/tizen_renderer.h @@ -12,7 +12,7 @@ namespace flutter { class TizenRenderer { public: - struct TizenWindowGeometry { + struct WindowGeometry { int32_t x{0}, y{0}, w{0}, h{0}; }; @@ -32,7 +32,7 @@ class TizenRenderer { virtual uint32_t OnGetFBO() = 0; virtual void* OnProcResolver(const char* name) = 0; - virtual TizenWindowGeometry GetGeometry() = 0; + virtual WindowGeometry GetCurrentGeometry() = 0; virtual int32_t GetDpi() = 0; virtual uintptr_t GetWindowId() = 0; @@ -45,12 +45,13 @@ class TizenRenderer { virtual void SetPreferredOrientations(const std::vector& rotations) = 0; protected: - explicit TizenRenderer(TizenRenderer::Delegate& delegate); + explicit TizenRenderer(WindowGeometry geometry, Delegate& delegate); - bool is_valid_ = false; + WindowGeometry initial_geometry_; + Delegate& delegate_; - bool received_rotation_{false}; - TizenRenderer::Delegate& delegate_; + bool is_valid_ = false; + bool received_rotation_ = false; }; } // namespace flutter diff --git a/shell/platform/tizen/tizen_renderer_ecore_wl2.cc b/shell/platform/tizen/tizen_renderer_ecore_wl2.cc index 8b5b45f93e193..43dbb1a17d033 100644 --- a/shell/platform/tizen/tizen_renderer_ecore_wl2.cc +++ b/shell/platform/tizen/tizen_renderer_ecore_wl2.cc @@ -11,8 +11,9 @@ namespace flutter { -TizenRendererEcoreWl2::TizenRendererEcoreWl2(TizenRenderer::Delegate& delegate) - : TizenRenderer(delegate) { +TizenRendererEcoreWl2::TizenRendererEcoreWl2(WindowGeometry geometry, + Delegate& delegate) + : TizenRenderer(geometry, delegate) { InitializeRenderer(); } @@ -211,8 +212,8 @@ void* TizenRendererEcoreWl2::OnProcResolver(const char* name) { return nullptr; } -TizenRenderer::TizenWindowGeometry TizenRendererEcoreWl2::GetGeometry() { - TizenWindowGeometry result; +TizenRenderer::WindowGeometry TizenRendererEcoreWl2::GetCurrentGeometry() { + WindowGeometry result; ecore_wl2_window_geometry_get(ecore_wl2_window_, &result.x, &result.y, &result.w, &result.h); return result; @@ -233,20 +234,20 @@ uintptr_t TizenRendererEcoreWl2::GetWindowId() { bool TizenRendererEcoreWl2::InitializeRenderer() { int32_t width, height; - if (!SetupDisplay(width, height)) { - FT_LOGE("SetupDisplay fail"); + if (!SetupDisplay(&width, &height)) { + FT_LOGE("SetupDisplay failed."); return false; } if (!SetupEcoreWlWindow(width, height)) { - FT_LOGE("SetupEcoreWlWindow fail"); + FT_LOGE("SetupEcoreWlWindow failed."); return false; } if (!SetupEglWindow(width, height)) { - FT_LOGE("SetupEglWindow fail"); + FT_LOGE("SetupEglWindow failed."); return false; } if (!SetupEglSurface()) { - FT_LOGE("SetupEglSurface fail"); + FT_LOGE("SetupEglSurface failed."); return false; } Show(); @@ -265,38 +266,50 @@ void TizenRendererEcoreWl2::DestroyRenderer() { ShutdownDisplay(); } -bool TizenRendererEcoreWl2::SetupDisplay(int32_t& width, int32_t& height) { +bool TizenRendererEcoreWl2::SetupDisplay(int32_t* width, int32_t* height) { if (!ecore_wl2_init()) { - FT_LOGE("Could not initialize ecore_wl2"); + FT_LOGE("Could not initialize ecore_wl2."); return false; } ecore_wl2_display_ = ecore_wl2_display_connect(nullptr); if (ecore_wl2_display_ == nullptr) { - FT_LOGE("Display not found"); + FT_LOGE("Display not found."); return false; } - ecore_wl2_sync(); - ecore_wl2_display_screen_size_get(ecore_wl2_display_, &width, &height); + + ecore_wl2_display_screen_size_get(ecore_wl2_display_, width, height); + if (*width == 0 || *height == 0) { + FT_LOGE("Invalid screen size: %d x %d", *width, *height); + return false; + } + if (initial_geometry_.w > 0) { + *width = initial_geometry_.w; + } + if (initial_geometry_.h > 0) { + *height = initial_geometry_.h; + } + return true; } bool TizenRendererEcoreWl2::SetupEcoreWlWindow(int32_t width, int32_t height) { - if (width == 0 || height == 0) { - FT_LOGE("Invalid screen size: %d x %d", width, height); - return false; - } + int32_t x = initial_geometry_.x; + int32_t y = initial_geometry_.y; + ecore_wl2_window_ = - ecore_wl2_window_new(ecore_wl2_display_, nullptr, 0, 0, width, height); + ecore_wl2_window_new(ecore_wl2_display_, nullptr, x, y, width, height); ecore_wl2_window_type_set(ecore_wl2_window_, ECORE_WL2_WINDOW_TYPE_TOPLEVEL); ecore_wl2_window_alpha_set(ecore_wl2_window_, EINA_FALSE); - ecore_wl2_window_position_set(ecore_wl2_window_, 0, 0); + ecore_wl2_window_position_set(ecore_wl2_window_, x, y); ecore_wl2_window_aux_hint_add(ecore_wl2_window_, 0, "wm.policy.win.user.geometry", "1"); + int rotations[4] = {0, 90, 180, 270}; ecore_wl2_window_available_rotations_set(ecore_wl2_window_, rotations, sizeof(rotations) / sizeof(int)); ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_ROTATE, RotationEventCb, this); + return true; } diff --git a/shell/platform/tizen/tizen_renderer_ecore_wl2.h b/shell/platform/tizen/tizen_renderer_ecore_wl2.h index 42027bbb7d107..15378d5da022f 100644 --- a/shell/platform/tizen/tizen_renderer_ecore_wl2.h +++ b/shell/platform/tizen/tizen_renderer_ecore_wl2.h @@ -15,7 +15,7 @@ namespace flutter { class TizenRendererEcoreWl2 : public TizenRenderer { public: - explicit TizenRendererEcoreWl2(TizenRenderer::Delegate& delegate); + explicit TizenRendererEcoreWl2(WindowGeometry geometry, Delegate& delegate); virtual ~TizenRendererEcoreWl2(); bool OnMakeCurrent() override; @@ -25,7 +25,7 @@ class TizenRendererEcoreWl2 : public TizenRenderer { uint32_t OnGetFBO() override; void* OnProcResolver(const char* name) override; - TizenWindowGeometry GetGeometry() override; + WindowGeometry GetCurrentGeometry() override; int32_t GetDpi() override; uintptr_t GetWindowId() override; @@ -42,7 +42,7 @@ class TizenRendererEcoreWl2 : public TizenRenderer { void Show(); void DestroyRenderer(); - bool SetupDisplay(int32_t& width, int32_t& height); + bool SetupDisplay(int32_t* width, int32_t* height); bool SetupEcoreWlWindow(int32_t width, int32_t height); bool SetupEglWindow(int32_t width, int32_t height); EGLDisplay GetEGLDisplay(); diff --git a/shell/platform/tizen/tizen_renderer_evas_gl.cc b/shell/platform/tizen/tizen_renderer_evas_gl.cc index 8eb03cad262bc..d742be83ec48c 100644 --- a/shell/platform/tizen/tizen_renderer_evas_gl.cc +++ b/shell/platform/tizen/tizen_renderer_evas_gl.cc @@ -6,8 +6,6 @@ #ifdef __X64_SHELL__ #include "tizen_evas_gl_helper.h" -int gApp_width = 800; -int gApp_height = 600; #else #include #endif @@ -18,8 +16,9 @@ EVAS_GL_GLOBAL_GLES3_DEFINE(); namespace flutter { -TizenRendererEvasGL::TizenRendererEvasGL(TizenRenderer::Delegate& delegate) - : TizenRenderer(delegate) { +TizenRendererEvasGL::TizenRendererEvasGL(WindowGeometry geometry, + Delegate& delegate) + : TizenRenderer(geometry, delegate) { InitializeRenderer(); // Clear once to remove noise. @@ -549,8 +548,8 @@ void* TizenRendererEvasGL::OnProcResolver(const char* name) { return nullptr; } -TizenRenderer::TizenWindowGeometry TizenRendererEvasGL::GetGeometry() { - TizenWindowGeometry result; +TizenRenderer::WindowGeometry TizenRendererEvasGL::GetCurrentGeometry() { + WindowGeometry result; evas_object_geometry_get(evas_window_, &result.x, &result.y, &result.w, &result.h); return result; @@ -595,9 +594,10 @@ void TizenRendererEvasGL::DestroyRenderer() { bool TizenRendererEvasGL::SetupEvasGL() { int32_t width, height; - evas_gl_ = evas_gl_new(evas_object_evas_get(SetupEvasWindow(width, height))); + evas_gl_ = + evas_gl_new(evas_object_evas_get(SetupEvasWindow(&width, &height))); if (!evas_gl_) { - FT_LOGE("SetupEvasWindow fail"); + FT_LOGE("Could not set up an Evas window object."); return false; } @@ -640,27 +640,34 @@ bool TizenRendererEvasGL::SetupEvasGL() { return true; } -Evas_Object* TizenRendererEvasGL::SetupEvasWindow(int32_t& width, - int32_t& height) { +Evas_Object* TizenRendererEvasGL::SetupEvasWindow(int32_t* width, + int32_t* height) { elm_config_accel_preference_set("hw:opengl"); evas_window_ = elm_win_add(NULL, NULL, ELM_WIN_BASIC); + if (!evas_window_) { + return nullptr; + } auto* ecore_evas = ecore_evas_ecore_evas_get(evas_object_evas_get(evas_window_)); - int32_t x, y; - ecore_evas_screen_geometry_get(ecore_evas, &x, &y, &width, &height); - if (width == 0 || height == 0) { - FT_LOGE("Invalid screen size: %d x %d", width, height); + + ecore_evas_screen_geometry_get(ecore_evas, nullptr, nullptr, width, height); + if (*width == 0 || *height == 0) { + FT_LOGE("Invalid screen size: %d x %d", *width, *height); return nullptr; } + if (initial_geometry_.w > 0) { + *width = initial_geometry_.w; + } + if (initial_geometry_.h > 0) { + *height = initial_geometry_.h; + } + int32_t x = initial_geometry_.x; + int32_t y = initial_geometry_.y; -#ifdef __X64_SHELL__ - width = gApp_width; - height = gApp_height; -#endif elm_win_alpha_set(evas_window_, EINA_FALSE); - evas_object_move(evas_window_, 0, 0); - evas_object_resize(evas_window_, width, height); + evas_object_move(evas_window_, x, y); + evas_object_resize(evas_window_, *width, *height); evas_object_raise(evas_window_); Evas_Object* bg = elm_bg_add(evas_window_); @@ -671,9 +678,9 @@ Evas_Object* TizenRendererEvasGL::SetupEvasWindow(int32_t& width, graphics_adapter_ = evas_object_image_filled_add(evas_object_evas_get(evas_window_)); - evas_object_resize(graphics_adapter_, width, height); - evas_object_move(graphics_adapter_, 0, 0); - evas_object_image_size_set(graphics_adapter_, width, height); + evas_object_resize(graphics_adapter_, *width, *height); + evas_object_move(graphics_adapter_, x, y); + evas_object_image_size_set(graphics_adapter_, *width, *height); evas_object_image_alpha_set(graphics_adapter_, EINA_TRUE); elm_win_resize_object_add(evas_window_, graphics_adapter_); diff --git a/shell/platform/tizen/tizen_renderer_evas_gl.h b/shell/platform/tizen/tizen_renderer_evas_gl.h index 1eb0e8b15bf44..22f00bd906f22 100644 --- a/shell/platform/tizen/tizen_renderer_evas_gl.h +++ b/shell/platform/tizen/tizen_renderer_evas_gl.h @@ -16,7 +16,7 @@ namespace flutter { class TizenRendererEvasGL : public TizenRenderer { public: - explicit TizenRendererEvasGL(TizenRenderer::Delegate& delegate); + explicit TizenRendererEvasGL(WindowGeometry geometry, Delegate& delegate); virtual ~TizenRendererEvasGL(); bool OnMakeCurrent() override; @@ -26,7 +26,7 @@ class TizenRendererEvasGL : public TizenRenderer { uint32_t OnGetFBO() override; void* OnProcResolver(const char* name) override; - TizenWindowGeometry GetGeometry() override; + WindowGeometry GetCurrentGeometry() override; int32_t GetDpi() override; uintptr_t GetWindowId() override; @@ -48,7 +48,7 @@ class TizenRendererEvasGL : public TizenRenderer { void DestroyRenderer(); bool SetupEvasGL(); - Evas_Object* SetupEvasWindow(int32_t& width, int32_t& height); + Evas_Object* SetupEvasWindow(int32_t* width, int32_t* height); void DestroyEvasGL(); void DestroyEvasWindow(); diff --git a/shell/platform/tizen/touch_event_handler.cc b/shell/platform/tizen/touch_event_handler.cc index ac8a6baf8b9f5..8214ac1b94c32 100644 --- a/shell/platform/tizen/touch_event_handler.cc +++ b/shell/platform/tizen/touch_event_handler.cc @@ -39,9 +39,9 @@ void TouchEventHandler::SendFlutterPointerEvent(FlutterPointerPhase phase, size_t timestamp, int device_id = 0) { // Correct errors caused by window rotation. - auto window_geometry = engine_->renderer->GetGeometry(); - double width = window_geometry.w; - double height = window_geometry.h; + auto geometry = engine_->renderer->GetCurrentGeometry(); + double width = geometry.w; + double height = geometry.h; double new_x = x, new_y = y; if (rotation == 90) {