diff --git a/packages/geolocator/CHANGELOG.md b/packages/geolocator/CHANGELOG.md index 342f20105..f8e0e9b66 100644 --- a/packages/geolocator/CHANGELOG.md +++ b/packages/geolocator/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.3 + +* Refactor the C++ code. + ## 1.0.2 * Update geolocator to 8.0.0 diff --git a/packages/geolocator/pubspec.yaml b/packages/geolocator/pubspec.yaml index 7cddfc1ca..82fa2d975 100644 --- a/packages/geolocator/pubspec.yaml +++ b/packages/geolocator/pubspec.yaml @@ -2,7 +2,7 @@ name: geolocator_tizen description: Geolocation plugin for Flutter. This plugin provides the Tizen implementation for the geolocator. homepage: https://github.com/flutter-tizen/plugins repository: https://github.com/flutter-tizen/plugins/tree/master/packages/geolocator -version: 1.0.2 +version: 1.0.3 flutter: plugin: diff --git a/packages/geolocator/tizen/inc/geolocator_tizen_plugin.h b/packages/geolocator/tizen/inc/geolocator_tizen_plugin.h index ad06c03df..4cac3ff67 100644 --- a/packages/geolocator/tizen/inc/geolocator_tizen_plugin.h +++ b/packages/geolocator/tizen/inc/geolocator_tizen_plugin.h @@ -1,3 +1,7 @@ +// 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. + #ifndef FLUTTER_PLUGIN_GEOLOCATOR_TIZEN_PLUGIN_H_ #define FLUTTER_PLUGIN_GEOLOCATOR_TIZEN_PLUGIN_H_ diff --git a/packages/geolocator/tizen/src/app_settings_manager.cc b/packages/geolocator/tizen/src/app_settings_manager.cc new file mode 100644 index 000000000..902d93db5 --- /dev/null +++ b/packages/geolocator/tizen/src/app_settings_manager.cc @@ -0,0 +1,126 @@ +// 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 "app_settings_manager.h" + +#include +#include +#include + +#include + +#include "log.h" + +namespace { + +constexpr char kSettingAppId[] = "com.samsung.clocksetting.apps"; +constexpr char kLocationSettingAppId[] = "com.samsung.setting-location"; +constexpr char kLocationSettingOperationId[] = + "http://tizen.org/appcontrol/operation/configure/location"; + +std::string GetPackageName() { + char* app_id; + int ret = app_get_id(&app_id); + if (ret != APP_ERROR_NONE) { + LOG_ERROR("The app ID is not found."); + return ""; + } + + package_info_h package_info; + ret = package_info_create(app_id, &package_info); + free(app_id); + if (ret != PACKAGE_MANAGER_ERROR_NONE) { + LOG_ERROR("Failed to create a package info handle."); + return ""; + } + + char* package_name; + ret = package_info_get_package(package_info, &package_name); + package_info_destroy(package_info); + if (ret != PACKAGE_MANAGER_ERROR_NONE) { + LOG_ERROR("Failed to get the package name."); + return ""; + } + + std::string result = std::string(package_name); + free(package_name); + + return result; +} + +} // namespace + +bool AppSettingsManager::OpenAppSettings() { + std::string package_name = GetPackageName(); + if (package_name.empty()) { + return false; + } + + app_control_h app_control; + int ret = app_control_create(&app_control); + if (ret != APP_CONTROL_ERROR_NONE) { + LOG_ERROR("Failed to create an app control handle."); + return false; + } + + ret = app_control_set_app_id(app_control, kSettingAppId); + if (ret != APP_CONTROL_ERROR_NONE) { + LOG_ERROR("Failed to set an app ID."); + app_control_destroy(app_control); + return false; + } + + ret = app_control_add_extra_data(app_control, "pkgId", package_name.c_str()); + if (ret != APP_CONTROL_ERROR_NONE) { + LOG_ERROR("Failed to add extra data."); + app_control_destroy(app_control); + return false; + } + + ret = app_control_send_launch_request(app_control, nullptr, nullptr); + app_control_destroy(app_control); + if (ret != APP_CONTROL_ERROR_NONE) { + LOG_ERROR("Failed to send a launch request."); + return false; + } + + return true; +} + +bool AppSettingsManager::OpenLocationSettings() { + std::string package_name = GetPackageName(); + if (package_name.empty()) { + return false; + } + + app_control_h app_control; + int ret = app_control_create(&app_control); + if (ret != APP_CONTROL_ERROR_NONE) { + LOG_ERROR("Failed to create an app control handle."); + return false; + } + + ret = app_control_set_app_id(app_control, kLocationSettingAppId); + if (ret != APP_CONTROL_ERROR_NONE) { + LOG_ERROR("Failed to set an app ID."); + app_control_destroy(app_control); + return false; + } + + ret = app_control_set_operation(app_control, kLocationSettingOperationId); + if (ret != APP_CONTROL_ERROR_NONE) { + LOG_ERROR("Failed to set operation. (%s)", get_error_message(ret)); + app_control_destroy(app_control); + return false; + } + + ret = app_control_send_launch_request(app_control, nullptr, nullptr); + app_control_destroy(app_control); + if (ret != APP_CONTROL_ERROR_NONE) { + LOG_ERROR("Failed to send a launch request."); + return false; + } + + return true; +} diff --git a/packages/geolocator/tizen/src/app_settings_manager.h b/packages/geolocator/tizen/src/app_settings_manager.h new file mode 100644 index 000000000..0f424eaa2 --- /dev/null +++ b/packages/geolocator/tizen/src/app_settings_manager.h @@ -0,0 +1,17 @@ +// 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. + +#ifndef FLUTTER_PLUGIN_APP_SETTINGS_MANAGER_H_ +#define FLUTTER_PLUGIN_APP_SETTINGS_MANAGER_H_ + +class AppSettingsManager { + public: + AppSettingsManager() {} + ~AppSettingsManager() {} + + bool OpenAppSettings(); + bool OpenLocationSettings(); +}; + +#endif // FLUTTER_PLUGIN_APP_SETTINGS_MANAGER_H_ diff --git a/packages/geolocator/tizen/src/geolocator_tizen_plugin.cc b/packages/geolocator/tizen/src/geolocator_tizen_plugin.cc index 0c5035012..0a8ce728e 100644 --- a/packages/geolocator/tizen/src/geolocator_tizen_plugin.cc +++ b/packages/geolocator/tizen/src/geolocator_tizen_plugin.cc @@ -14,25 +14,130 @@ #include #include -#include "locaton_manager.h" -#include "log.h" +#include "app_settings_manager.h" +#include "location_manager.h" #include "permission_manager.h" -#include "setting.h" namespace { +typedef flutter::MethodChannel FlMethodChannel; +typedef flutter::EventChannel FlEventChannel; +typedef flutter::MethodCall FlMethodCall; +typedef flutter::EventSink FlEventSink; +typedef flutter::MethodResult FlMethodResult; +typedef flutter::StreamHandler FlStreamHandler; +typedef flutter::StreamHandlerError + FlStreamHandlerError; + +constexpr char kPrivilegeLocation[] = "http://tizen.org/privilege/location"; + +class LocationStreamHandler : public FlStreamHandler { + protected: + std::unique_ptr OnListenInternal( + const flutter::EncodableValue *arguments, + std::unique_ptr &&events) override { + events_ = std::move(events); + LocationCallback callback = [this](Position position) -> void { + events_->Success(position.ToEncodableValue()); + }; + try { + location_manager_.StartListenLocationUpdate(callback); + } catch (const LocationManagerError &error) { + // Issue: https://github.com/flutter/flutter/issues/101682 + error_code_ = std::to_string(error.GetErrorCode()); + error_message_ = error.GetErrorString(); + return std::make_unique(error_code_, error_message_, + nullptr); + } + return nullptr; + } + + std::unique_ptr OnCancelInternal( + const flutter::EncodableValue *arguments) override { + try { + location_manager_.StopListenLocationUpdate(); + } catch (const LocationManagerError &error) { + error_code_ = std::to_string(error.GetErrorCode()); + error_message_ = error.GetErrorString(); + return std::make_unique(error_code_, error_message_, + nullptr); + } + events_.reset(); + return nullptr; + } + + private: + LocationManager location_manager_; + std::unique_ptr events_; + + std::string error_code_; + std::string error_message_; +}; + +class ServiceStatusStreamHandler : public FlStreamHandler { + protected: + std::unique_ptr OnListenInternal( + const flutter::EncodableValue *arguments, + std::unique_ptr &&events) override { + events_ = std::move(events); + ServiceStatusCallback callback = [this](ServiceStatus status) -> void { + events_->Success(flutter::EncodableValue(static_cast(status))); + }; + try { + location_manager_.StartListenServiceStatusUpdate(callback); + } catch (const LocationManagerError &error) { + // Issue: https://github.com/flutter/flutter/issues/101682 + error_code_ = std::to_string(error.GetErrorCode()); + error_message_ = error.GetErrorString(); + return std::make_unique(error_code_, error_message_, + nullptr); + } + return nullptr; + } + + std::unique_ptr OnCancelInternal( + const flutter::EncodableValue *arguments) override { + try { + location_manager_.StopListenServiceStatusUpdate(); + } catch (const LocationManagerError &error) { + error_code_ = std::to_string(error.GetErrorCode()); + error_message_ = error.GetErrorString(); + return std::make_unique(error_code_, error_message_, + nullptr); + } + events_.reset(); + return nullptr; + } + + private: + LocationManager location_manager_; + std::unique_ptr events_; + + std::string error_code_; + std::string error_message_; +}; + class GeolocatorTizenPlugin : public flutter::Plugin { public: static void RegisterWithRegistrar(flutter::PluginRegistrar *registrar) { - auto channel = - std::make_unique>( - registrar->messenger(), "flutter.baseflow.com/geolocator", - &flutter::StandardMethodCodec::GetInstance()); + auto channel = std::make_unique( + registrar->messenger(), "flutter.baseflow.com/geolocator", + &flutter::StandardMethodCodec::GetInstance()); auto plugin = std::make_unique(); - plugin->SetupGeolocatorServiceUpdatesChannel(registrar->messenger()); - plugin->SetupGeolocatorUpdatesChannel(registrar->messenger()); + plugin->service_updates_channel_ = std::make_unique( + registrar->messenger(), + "flutter.baseflow.com/geolocator_service_updates", + &flutter::StandardMethodCodec::GetInstance()); + plugin->service_updates_channel_->SetStreamHandler( + std::make_unique()); + + plugin->updates_channel_ = std::make_unique( + registrar->messenger(), "flutter.baseflow.com/geolocator_updates", + &flutter::StandardMethodCodec::GetInstance()); + plugin->updates_channel_->SetStreamHandler( + std::make_unique()); channel->SetMethodCallHandler( [plugin_pointer = plugin.get()](const auto &call, auto result) { @@ -49,200 +154,116 @@ class GeolocatorTizenPlugin : public flutter::Plugin { virtual ~GeolocatorTizenPlugin() {} private: - void SetupGeolocatorServiceUpdatesChannel( - flutter::BinaryMessenger *messenger) { - geolocator_service_updates_channel_ = - std::make_unique>( - messenger, "flutter.baseflow.com/geolocator_service_updates", - &flutter::StandardMethodCodec::GetInstance()); - auto handler = std::make_unique>( - [this](const flutter::EncodableValue *arguments, - std::unique_ptr> &&events) - -> std::unique_ptr> { - OnListenGeolocatorServiceUpdates(std::move(events)); - return nullptr; - }, - [this](const flutter::EncodableValue *arguments) - -> std::unique_ptr> { - OnCancelGeolocatorServiceUpdates(); - return nullptr; - }); - geolocator_service_updates_channel_->SetStreamHandler(std::move(handler)); - } + void HandleMethodCall(const FlMethodCall &method_call, + std::unique_ptr result) { + std::string method_name = method_call.method_name(); - void SetupGeolocatorUpdatesChannel(flutter::BinaryMessenger *messenger) { - geolocator_updates_channel_ = - std::make_unique>( - messenger, "flutter.baseflow.com/geolocator_updates", - &flutter::StandardMethodCodec::GetInstance()); - auto handler = std::make_unique>( - [this](const flutter::EncodableValue *arguments, - std::unique_ptr> &&events) - -> std::unique_ptr> { - OnListenGeolocatorUpdates(std::move(events)); - return nullptr; - }, - [this](const flutter::EncodableValue *arguments) - -> std::unique_ptr> { - OnCancelGeolocatorUpdates(); - return nullptr; - }); - geolocator_updates_channel_->SetStreamHandler(std::move(handler)); - } + result_ = std::move(result); - void HandleMethodCall( - const flutter::MethodCall &method_call, - std::unique_ptr> result) { - std::string method_name = method_call.method_name(); if (method_name == "checkPermission") { - OnCheckPermission(std::move(result)); + OnCheckPermission(); } else if (method_name == "isLocationServiceEnabled") { - OnIsLocationServiceEnabled(std::move(result)); + OnIsLocationServiceEnabled(); } else if (method_name == "requestPermission") { - OnRequestPermission(std::move(result)); + OnRequestPermission(); } else if (method_name == "getLastKnownPosition") { - OnGetLastKnownPosition(std::move(result)); + OnGetLastKnownPosition(); } else if (method_name == "getCurrentPosition") { - OnGetCurrentPosition(std::move(result)); + OnGetCurrentPosition(); } else if (method_name == "openAppSettings") { - TizenResult ret = Setting::LaunchAppSetting(); - result->Success(flutter::EncodableValue(static_cast(ret))); + bool opened = app_settings_manager_->OpenAppSettings(); + SendResult(flutter::EncodableValue(opened)); } else if (method_name == "openLocationSettings") { - TizenResult ret = Setting::LaunchLocationSetting(); - result->Success(flutter::EncodableValue(static_cast(ret))); + bool opened = app_settings_manager_->OpenLocationSettings(); + SendResult(flutter::EncodableValue(opened)); } else { result->NotImplemented(); } } - void OnCheckPermission( - std::unique_ptr> result) { - PermissionStatus permission_status; - TizenResult ret = - permission_manager_->CheckPermissionStatus(&permission_status); - if (!ret) { - result->Error("Failed to check permssion status.", ret.message()); + void OnCheckPermission() { + PermissionStatus result = + permission_manager_->CheckPermission(kPrivilegeLocation); + if (result == PermissionStatus::kError) { + SendErrorResult("Operation failed", "Permission check failed."); return; } - LOG_INFO("permission_status is %d", permission_status); - result->Success( - flutter::EncodableValue(static_cast(permission_status))); + SendResult(flutter::EncodableValue(static_cast(result))); } - void OnIsLocationServiceEnabled( - std::unique_ptr> result) { - bool is_enabled = false; - TizenResult ret = location_manager_->IsLocationServiceEnabled(&is_enabled); - - // TODO : add location service listener - if (!ret) { - result->Error("Failed to check service enabled.", ret.message()); + void OnIsLocationServiceEnabled() { + try { + bool is_enabled = location_manager_->IsLocationServiceEnabled(); + SendResult(flutter::EncodableValue(is_enabled)); + } catch (const LocationManagerError &error) { + SendErrorResult("Operation failed", error.GetErrorString()); } - result->Success(flutter::EncodableValue(is_enabled)); } - void OnRequestPermission( - std::unique_ptr> result) { - auto result_ptr = result.release(); - permission_manager_->RequestPermssion( - [result_ptr](PermissionStatus permission_status) { - result_ptr->Success( - flutter::EncodableValue(static_cast(permission_status))); - delete result_ptr; - }, - [result_ptr](TizenResult tizen_result) { - result_ptr->Error("Failed to request permssion.", - tizen_result.message()); - delete result_ptr; - }); - } + void OnRequestPermission() { + PermissionStatus result = + permission_manager_->RequestPermission(kPrivilegeLocation); - void OnGetLastKnownPosition( - std::unique_ptr> result) { - Location location; - TizenResult tizen_result = - location_manager_->GetLastKnownLocation(&location); - if (!tizen_result) { - result->Error("Failed to get last known position.", - tizen_result.message()); + if (result == PermissionStatus::kError) { + SendErrorResult("Operation failed", "Permission request failed."); + return; + } else if (result == PermissionStatus::kDeniedForever || + result == PermissionStatus::kDenied) { + SendErrorResult("Permission denied", "Permission denied by user."); return; } - result->Success(location.ToEncodableValue()); + SendResult(flutter::EncodableValue(static_cast(result))); } - void OnGetCurrentPosition( - std::unique_ptr> result) { - auto result_ptr = result.release(); - TizenResult tizen_result = location_manager_->RequestCurrentLocationOnce( - [result_ptr](Location location) { - result_ptr->Success(location.ToEncodableValue()); - delete result_ptr; - }, - [result_ptr](TizenResult error) { - result_ptr->Error( - "An error occurred while requesting current location.", - error.message()); - delete result_ptr; - }); - - if (!tizen_result) { - result_ptr->Error("Failed to call RequestCurrentLocationOnce.", - tizen_result.message()); - delete result_ptr; + void OnGetLastKnownPosition() { + try { + Position position = location_manager_->GetLastKnownPosition(); + SendResult(position.ToEncodableValue()); + } catch (const LocationManagerError &error) { + SendErrorResult("Operation failed", error.GetErrorString()); } } - void OnListenGeolocatorServiceUpdates( - std::unique_ptr> - &&event_sink) { - geolocator_service_updates_event_sink_ = std::move(event_sink); - TizenResult tizen_result = location_manager_->SetOnServiceStateChanged( - [this](ServiceState service_state) { - flutter::EncodableValue value(static_cast(service_state)); - geolocator_service_updates_event_sink_->Success(value); + void OnGetCurrentPosition() { + auto result_ptr = result_.release(); + location_manager_->GetCurrentPosition( + [result_ptr](Position position) { + if (result_ptr) { + result_ptr->Success(position.ToEncodableValue()); + delete result_ptr; + } + }, + [result_ptr](LocationManagerError error) { + if (result_ptr) { + result_ptr->Error("Operation failed", error.GetErrorString()); + delete result_ptr; + } }); - if (!tizen_result) { - LOG_ERROR("Failed to set OnServiceStateChanged, %s.", - tizen_result.message().c_str()); - geolocator_service_updates_event_sink_ = nullptr; - } } - void OnCancelGeolocatorServiceUpdates() { - geolocator_service_updates_event_sink_ = nullptr; - location_manager_->UnsetOnServiceStateChanged(); - } - - void OnListenGeolocatorUpdates( - std::unique_ptr> - &&event_sink) { - geolocator_updates_event_sink_ = std::move(event_sink); - TizenResult tizen_result = - location_manager_->SetOnLocationUpdated([this](Location location) { - geolocator_updates_event_sink_->Success(location.ToEncodableValue()); - }); - if (!tizen_result) { - LOG_ERROR("Failed to set OnLocationUpdated, %s.", - tizen_result.message().c_str()); - geolocator_updates_event_sink_ = nullptr; + void SendResult(const flutter::EncodableValue &result) { + if (!result_) { + return; } + result_->Success(result); + result_ = nullptr; } - void OnCancelGeolocatorUpdates() { - geolocator_updates_event_sink_ = nullptr; - location_manager_->UnsetOnLocationUpdated(); + void SendErrorResult(const std::string &error_code, + const std::string &error_message) { + if (!result_) { + return; + } + result_->Error(error_code, error_message); + result_ = nullptr; } + std::unique_ptr result_; std::unique_ptr permission_manager_; std::unique_ptr location_manager_; - std::unique_ptr> - geolocator_service_updates_channel_; - std::unique_ptr> - geolocator_service_updates_event_sink_; - std::unique_ptr> - geolocator_updates_channel_; - std::unique_ptr> - geolocator_updates_event_sink_; + std::unique_ptr app_settings_manager_; + std::unique_ptr service_updates_channel_; + std::unique_ptr updates_channel_; }; } // namespace diff --git a/packages/geolocator/tizen/src/location_manager.cc b/packages/geolocator/tizen/src/location_manager.cc new file mode 100644 index 000000000..2992cfd95 --- /dev/null +++ b/packages/geolocator/tizen/src/location_manager.cc @@ -0,0 +1,163 @@ +// 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 "location_manager.h" + +LocationManager::LocationManager() { + location_manager_create(LOCATIONS_METHOD_HYBRID, &manager_); + location_manager_create(LOCATIONS_METHOD_HYBRID, + &manager_for_current_location_); +} + +LocationManager::~LocationManager() { + location_manager_destroy(manager_); + location_manager_destroy(manager_for_current_location_); +} + +bool LocationManager::IsLocationServiceEnabled() { + bool gps_enabled = false; + int ret = + location_manager_is_enabled_method(LOCATIONS_METHOD_GPS, &gps_enabled); + if (LOCATIONS_ERROR_NONE != ret) { + throw LocationManagerError(ret); + } + + bool wps_enabled = false; + ret = location_manager_is_enabled_method(LOCATIONS_METHOD_WPS, &wps_enabled); + if (LOCATIONS_ERROR_NONE != ret) { + throw LocationManagerError(ret); + } + return gps_enabled || wps_enabled; +} + +Position LocationManager::GetLastKnownPosition() { + double altitude = 0.0; + double latitude = 0.0; + double longitude = 0.0; + double climb = 0.0; + double direction = 0.0; + double speed = 0.0; + double horizontal = 0.0; + double vertical = 0.0; + location_accuracy_level_e level = LOCATIONS_ACCURACY_NONE; + time_t timestamp = 0; + + int ret = location_manager_get_last_location( + manager_, &altitude, &latitude, &longitude, &climb, &direction, &speed, + &level, &horizontal, &vertical, ×tamp); + if (LOCATIONS_ERROR_NONE != ret) { + throw LocationManagerError(ret); + } + Position position; + position.longitude = longitude; + position.latitude = latitude; + position.timestamp = timestamp; + position.accuracy = horizontal; + position.altitude = altitude; + position.heading = direction; + position.speed = speed; + + return position; +} + +void LocationManager::GetCurrentPosition(LocationCallback on_location, + LocationErrorCallback on_error) { + location_callback_ = on_location; + error_callback_ = on_error; + int ret = location_manager_request_single_location( + manager_for_current_location_, 5, + [](location_error_e error, double latitude, double longitude, + double altitude, time_t timestamp, double speed, double direction, + double climb, void *user_data) { + LocationManager *self = static_cast(user_data); + + if (error != LOCATIONS_ERROR_NONE && self->error_callback_) { + self->error_callback_(LocationManagerError(error)); + } else if (self->location_callback_) { + Position position; + position.latitude = latitude; + position.longitude = longitude; + position.altitude = altitude; + position.timestamp = timestamp; + position.speed = speed; + position.heading = direction; + + self->location_callback_(position); + } + self->location_callback_ = nullptr; + self->error_callback_ = nullptr; + }, + this); + if (LOCATIONS_ERROR_NONE != ret) { + error_callback_(LocationManagerError(ret)); + error_callback_ = nullptr; + } +} + +void LocationManager::StartListenServiceStatusUpdate( + ServiceStatusCallback on_service_status_update) { + service_status_update_callback_ = on_service_status_update; + int ret = location_manager_set_service_state_changed_cb( + manager_, + [](location_service_state_e state, void *user_data) { + LocationManager *self = static_cast(user_data); + if (self->service_status_update_callback_) { + ServiceStatus service_status = ServiceStatus::kDisabled; + if (state == LOCATIONS_SERVICE_ENABLED) { + service_status = ServiceStatus::kEnabled; + } + self->service_status_update_callback_(service_status); + } + }, + this); + if (LOCATIONS_ERROR_NONE != ret) { + throw LocationManagerError(ret); + } +} + +void LocationManager::StopListenServiceStatusUpdate() { + int ret = location_manager_unset_service_state_changed_cb(manager_); + if (LOCATIONS_ERROR_NONE != ret) { + throw LocationManagerError(ret); + } +} + +void LocationManager::StartListenLocationUpdate( + LocationCallback on_location_update) { + location_update_callback_ = on_location_update; + + int ret = location_manager_set_position_updated_cb( + manager_, + [](double latitude, double longitude, double altitude, time_t timestamp, + void *user_data) { + LocationManager *self = static_cast(user_data); + if (self->location_update_callback_) { + Position position; + position.longitude = longitude; + position.latitude = latitude; + position.timestamp = timestamp; + position.altitude = altitude; + self->location_update_callback_(position); + } + }, + 2, this); + if (LOCATIONS_ERROR_NONE != ret) { + throw LocationManagerError(ret); + } + ret = location_manager_start(manager_); + if (LOCATIONS_ERROR_NONE != ret) { + throw LocationManagerError(ret); + } +} + +void LocationManager::StopListenLocationUpdate() { + int ret = location_manager_unset_position_updated_cb(manager_); + if (LOCATIONS_ERROR_NONE != ret) { + throw LocationManagerError(ret); + } + ret = location_manager_stop(manager_); + if (LOCATIONS_ERROR_NONE != ret) { + throw LocationManagerError(ret); + } +} diff --git a/packages/geolocator/tizen/src/location_manager.h b/packages/geolocator/tizen/src/location_manager.h new file mode 100644 index 000000000..6bd3f9de5 --- /dev/null +++ b/packages/geolocator/tizen/src/location_manager.h @@ -0,0 +1,69 @@ +// Copyright 2022 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. + +#ifndef FLUTTER_PLUGIN_LOCATION_MANAGER_H_ +#define FLUTTER_PLUGIN_LOCATION_MANAGER_H_ + +#include +#include + +#include +#include + +#include "position.h" + +// Defined in: +// https://github.com/Baseflow/flutter-geolocator/blob/master/geolocator_platform_interface/lib/src/enums/location_service.dart +enum class ServiceStatus { kDisabled, kEnabled }; + +class LocationManagerError { + public: + LocationManagerError(int error_code) : error_code_(error_code) {} + + int GetErrorCode() const { return error_code_; } + + std::string GetErrorString() const { return get_error_message(error_code_); } + + private: + int error_code_; +}; + +typedef std::function LocationCallback; +typedef std::function ServiceStatusCallback; +typedef std::function LocationErrorCallback; + +class LocationManager { + public: + LocationManager(); + ~LocationManager(); + + bool IsLocationServiceEnabled(); + + Position GetLastKnownPosition(); + + void GetCurrentPosition(LocationCallback on_location, + LocationErrorCallback on_error); + + void StartListenServiceStatusUpdate( + ServiceStatusCallback on_service_status_update); + + void StopListenServiceStatusUpdate(); + + void StartListenLocationUpdate(LocationCallback on_location_update); + + void StopListenLocationUpdate(); + + private: + // According to the document, the handler to request current location once + // must not be the same as a handler to listen position updates. + location_manager_h manager_for_current_location_ = nullptr; + location_manager_h manager_ = nullptr; + + ServiceStatusCallback service_status_update_callback_; + LocationCallback location_update_callback_; + LocationCallback location_callback_; + LocationErrorCallback error_callback_; +}; + +#endif // FLUTTER_PLUGIN_LOCATION_MANAGER_H_ diff --git a/packages/geolocator/tizen/src/locaton_manager.cc b/packages/geolocator/tizen/src/locaton_manager.cc deleted file mode 100644 index 9daf331a2..000000000 --- a/packages/geolocator/tizen/src/locaton_manager.cc +++ /dev/null @@ -1,160 +0,0 @@ -// 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 "locaton_manager.h" - -#include "log.h" - -LocationManager::LocationManager() { - CreateLocationManager(&manager_); - CreateLocationManager(&manager_for_current_location_); -} - -LocationManager::~LocationManager() { - DestroyLocationManager(manager_); - DestroyLocationManager(manager_for_current_location_); -} - -TizenResult LocationManager::IsLocationServiceEnabled(bool *is_enabled) { - bool gps_enabled = false; - int ret_gps = - location_manager_is_enabled_method(LOCATIONS_METHOD_GPS, &gps_enabled); - if (ret_gps != LOCATIONS_ERROR_NONE) { - return TizenResult(ret_gps); - } - - bool wps_enabled = false; - int ret_wps = - location_manager_is_enabled_method(LOCATIONS_METHOD_WPS, &wps_enabled); - if (ret_wps != LOCATIONS_ERROR_NONE) { - return TizenResult(ret_wps); - } - - *is_enabled = gps_enabled || wps_enabled; - - return TizenResult(); -} - -TizenResult LocationManager::RequestCurrentLocationOnce( - OnLocationUpdated on_success, OnError on_error) { - on_success_ = on_success; - on_error_ = on_error; - TizenResult ret = location_manager_request_single_location( - manager_for_current_location_, 5, - [](location_error_e error, double latitude, double longitude, - double altitude, time_t timestamp, double speed, double direction, - double climb, void *user_data) { - LocationManager *self = static_cast(user_data); - - if (error != LOCATIONS_ERROR_NONE && self->on_error_) { - self->on_error_(error); - } else if (self->on_success_) { - Location location; - location.latitude = latitude; - location.longitude = longitude; - location.altitude = altitude; - location.timestamp = timestamp; - location.speed = speed; - location.heading = direction; - - self->on_success_(location); - } - - self->on_error_ = nullptr; - self->on_success_ = nullptr; - }, - this); - return ret; -} - -TizenResult LocationManager::GetLastKnownLocation(Location *location) { - double altitude = 0.0; - double latitude = 0.0; - double longitude = 0.0; - double climb = 0.0; - double direction = 0.0; - double speed = 0.0; - double horizontal = 0.0; - double vertical = 0.0; - location_accuracy_level_e level = LOCATIONS_ACCURACY_NONE; - time_t timestamp = 0; - - TizenResult ret = location_manager_get_last_location( - manager_, &altitude, &latitude, &longitude, &climb, &direction, &speed, - &level, &horizontal, &vertical, ×tamp); - if (!ret) { - return ret; - } - - location->longitude = longitude; - location->latitude = latitude; - location->timestamp = timestamp; - location->accuracy = horizontal; - location->altitude = altitude; - location->heading = direction; - location->speed = speed; - - return ret; -} - -TizenResult LocationManager::SetOnServiceStateChanged( - OnServiceStateChanged on_service_state_changed) { - on_service_state_changed_ = on_service_state_changed; - return location_manager_set_service_state_changed_cb( - manager_, - [](location_service_state_e state, void *user_data) { - LocationManager *self = static_cast(user_data); - if (self->on_service_state_changed_) { - ServiceState service_state = ServiceState::kDisabled; - if (state == LOCATIONS_SERVICE_ENABLED) { - service_state = ServiceState::kEnabled; - } - self->on_service_state_changed_(service_state); - } - }, - this); -} - -TizenResult LocationManager::UnsetOnServiceStateChanged() { - return location_manager_unset_service_state_changed_cb(manager_); -} - -TizenResult LocationManager::SetOnLocationUpdated( - OnLocationUpdated on_location_updated) { - on_location_updated_ = on_location_updated; - TizenResult result = location_manager_set_position_updated_cb( - manager_, - [](double latitude, double longitude, double altitude, time_t timestamp, - void *user_data) { - LocationManager *self = static_cast(user_data); - if (self->on_location_updated_) { - Location location; - location.longitude = longitude; - location.latitude = latitude; - location.timestamp = timestamp; - location.altitude = altitude; - self->on_location_updated_(location); - } - }, - 2, this); - if (!result) { - return result; - } - return location_manager_start(manager_); -} - -TizenResult LocationManager::UnsetOnLocationUpdated() { - location_manager_unset_position_updated_cb(manager_); - return location_manager_stop(manager_); -} - -TizenResult LocationManager::CreateLocationManager( - location_manager_h *manager) { - return location_manager_create(LOCATIONS_METHOD_HYBRID, manager); -} - -TizenResult LocationManager::DestroyLocationManager( - location_manager_h manager) { - return location_manager_destroy(manager); -} diff --git a/packages/geolocator/tizen/src/locaton_manager.h b/packages/geolocator/tizen/src/locaton_manager.h deleted file mode 100644 index 12d14ba98..000000000 --- a/packages/geolocator/tizen/src/locaton_manager.h +++ /dev/null @@ -1,60 +0,0 @@ -// 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. - -#ifndef LOCATON_MANAGER_H_ -#define LOCATON_MANAGER_H_ - -#include - -#include - -#include "location.h" -#include "tizen_result.h" - -// Defined in: -// https://github.com/Baseflow/flutter-geolocator/blob/master/geolocator_platform_interface/lib/src/enums/location_service.dart -enum class ServiceState { kDisabled, kEnabled }; - -using OnLocationUpdated = std::function; -using OnError = std::function; -using OnServiceStateChanged = std::function; - -class LocationManager { - public: - LocationManager(); - ~LocationManager(); - - TizenResult IsLocationServiceEnabled(bool* is_enabled); - - TizenResult RequestCurrentLocationOnce(OnLocationUpdated on_success, - OnError on_error); - - TizenResult GetLastKnownLocation(Location* locaton); - - TizenResult SetOnServiceStateChanged( - OnServiceStateChanged on_service_state_changed); - - TizenResult UnsetOnServiceStateChanged(); - - TizenResult SetOnLocationUpdated(OnLocationUpdated on_location_updated); - - TizenResult UnsetOnLocationUpdated(); - - private: - TizenResult CreateLocationManager(location_manager_h* manager); - - TizenResult DestroyLocationManager(location_manager_h manager); - - location_manager_h manager_ = nullptr; - - // According to the document, the handler to request current location once - // must not be the same as a handler to listen position updated. - location_manager_h manager_for_current_location_ = nullptr; - - OnLocationUpdated on_success_; - OnError on_error_; - OnServiceStateChanged on_service_state_changed_; - OnLocationUpdated on_location_updated_; -}; -#endif // LOCATON_MANAGER_H_ diff --git a/packages/geolocator/tizen/src/permission_manager.cc b/packages/geolocator/tizen/src/permission_manager.cc index 3a70fdc5a..981bfa1ff 100644 --- a/packages/geolocator/tizen/src/permission_manager.cc +++ b/packages/geolocator/tizen/src/permission_manager.cc @@ -1,97 +1,87 @@ -// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved. +// Copyright 2022 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 "permission_manager.h" +#ifndef TV_PROFILE #include #include - -#include +#include +#endif #include "log.h" -namespace { - -constexpr char kPrivilegeLocation[] = "http://tizen.org/privilege/location"; - -struct PermissionResponse { - ppm_call_cause_e cause; - ppm_request_result_e result; - bool received = false; -}; - -} // namespace - -PermissionManager::PermissionManager() {} -PermissionManager::~PermissionManager() {} - -TizenResult PermissionManager::CheckPermissionStatus( - PermissionStatus *permission_status) { - ppm_check_result_e check_result; - - int result = ppm_check_permission(kPrivilegeLocation, &check_result); - if (result != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) { - return TizenResult(result); +PermissionStatus PermissionManager::CheckPermission( + const std::string &privilege) { +#ifdef TV_PROFILE + return PermissionStatus::kAlways; +#else + ppm_check_result_e result; + int ret = ppm_check_permission(privilege.c_str(), &result); + if (ret != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) { + LOG_ERROR("Permission check failed [%s]: %s", privilege.c_str(), + get_error_message(ret)); + return PermissionStatus::kError; } - switch (check_result) { - case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_DENY: - case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ASK: - *permission_status = PermissionStatus::kDenied; - break; + switch (result) { case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ALLOW: + return PermissionStatus::kAlways; + case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ASK: + case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_DENY: default: - *permission_status = PermissionStatus::kAlways; - break; + return PermissionStatus::kDenied; } - return TizenResult(); +#endif } -void PermissionManager::RequestPermssion(const OnSuccess &on_success, - const OnFailure &on_failure) { - const char *permission = kPrivilegeLocation; - PermissionResponse response; +PermissionStatus PermissionManager::RequestPermission( + const std::string &privilege) { +#ifdef TV_PROFILE + return PermissionStatus::kAlways; +#else + struct Response { + bool received = false; + ppm_call_cause_e cause; + ppm_request_result_e result; + } response; + int ret = ppm_request_permission( - permission, + privilege.c_str(), [](ppm_call_cause_e cause, ppm_request_result_e result, - const char *privilege, void *data) { - PermissionResponse *response = static_cast(data); + const char *privilege, void *user_data) { + auto *response = static_cast(user_data); + response->received = true; response->cause = cause; response->result = result; - response->received = true; }, &response); + if (ret != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) { - LOG_ERROR("Failed to call ppm_request_permission with [%s].", permission); - on_failure(TizenResult(ret)); - return; + LOG_ERROR("Permission request failed [%s]: %s", privilege.c_str(), + get_error_message(ret)); + return PermissionStatus::kError; } - // Wait until ppm_request_permission is done. + // Wait until ppm_request_permission() completes with a response. while (!response.received) { ecore_main_loop_iterate(); } - if (response.cause != PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ANSWER) { - LOG_ERROR("permission[%s] request failed with an error.", permission); - on_failure(TizenResult(ret)); - return; + if (response.cause == PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ERROR) { + LOG_ERROR("Received an error response [%s].", privilege.c_str()); + return PermissionStatus::kError; } switch (response.result) { case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_ALLOW_FOREVER: - on_success(PermissionStatus::kAlways); - break; - case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_DENY_ONCE: - on_success(PermissionStatus::kDenied); - break; + return PermissionStatus::kAlways; case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_DENY_FOREVER: - on_success(PermissionStatus::kDeniedForever); - break; + return PermissionStatus::kDeniedForever; + case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_DENY_ONCE: default: - LOG_ERROR("Unknown ppm_request_result_e."); - on_failure(TizenResult(ret)); - break; + return PermissionStatus::kDenied; } +#endif // TV_PROFILE } diff --git a/packages/geolocator/tizen/src/permission_manager.h b/packages/geolocator/tizen/src/permission_manager.h index 0a92465b8..43bde52f3 100644 --- a/packages/geolocator/tizen/src/permission_manager.h +++ b/packages/geolocator/tizen/src/permission_manager.h @@ -1,15 +1,12 @@ -// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved. +// Copyright 2022 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. -#ifndef PERMISSION_MANAGER_H_ -#define PERMISSION_MANAGER_H_ +#ifndef FLUTTER_PLUGIN_PERMISSION_MANAGER_H_ +#define FLUTTER_PLUGIN_PERMISSION_MANAGER_H_ -#include #include -#include "tizen_result.h" - // Keep in sync with the enum values implemented in: // https://github.com/Baseflow/flutter-geolocator/blob/master/geolocator_platform_interface/lib/src/enums/location_permission.dart // https://github.com/Baseflow/flutter-geolocator/blob/master/geolocator_android/android/src/main/java/com/baseflow/geolocator/permission/LocationPermission.java @@ -18,19 +15,17 @@ enum class PermissionStatus { kDeniedForever = 1, kWhileInUse = 2, kAlways = 3, + kError = 4 // tizen only. }; -using OnSuccess = std::function; -using OnFailure = std::function; class PermissionManager { public: - PermissionManager(); - ~PermissionManager(); + PermissionManager() {} + ~PermissionManager() {} - TizenResult CheckPermissionStatus(PermissionStatus *permission_status); + PermissionStatus CheckPermission(const std::string &privilege); - void RequestPermssion(const OnSuccess &on_success, - const OnFailure &on_failure); + PermissionStatus RequestPermission(const std::string &privilege); }; -#endif // PERMISSION_MANAGER_H_ +#endif // FLUTTER_PLUGIN_PERMISSION_MANAGER_H_ diff --git a/packages/geolocator/tizen/src/location.h b/packages/geolocator/tizen/src/position.h similarity index 92% rename from packages/geolocator/tizen/src/location.h rename to packages/geolocator/tizen/src/position.h index b9f2eda15..0952e4174 100644 --- a/packages/geolocator/tizen/src/location.h +++ b/packages/geolocator/tizen/src/position.h @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifndef FLUTTER_PLUGIN_POSITION_H_ +#define FLUTTER_PLUGIN_POSITION_H_ + #include #include @@ -10,7 +13,7 @@ // Defined in: // https://github.com/Baseflow/flutter-geolocator/blob/master/geolocator_platform_interface/lib/src/models/position.dart -struct Location { +struct Position { flutter::EncodableValue ToEncodableValue() { flutter::EncodableMap values = { {flutter::EncodableValue("longitude"), @@ -50,3 +53,5 @@ struct Location { std::optional speed; std::optional speedAccuracy; }; + +#endif // FLUTTER_PLUGIN_POSITION_H_ diff --git a/packages/geolocator/tizen/src/setting.cc b/packages/geolocator/tizen/src/setting.cc deleted file mode 100644 index 507984819..000000000 --- a/packages/geolocator/tizen/src/setting.cc +++ /dev/null @@ -1,96 +0,0 @@ -// 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 "setting.h" - -#include -#include -#include - -namespace { - -class AppControl { - public: - AppControl() { app_control_create(&app_control_); } - - ~AppControl() { app_control_destroy(app_control_); } - - TizenResult AddExtraData(const std::string& key, const std::string& value) { - return app_control_add_extra_data(app_control_, key.c_str(), value.c_str()); - } - - TizenResult SetAppId(const std::string& id) { - return app_control_set_app_id(app_control_, id.c_str()); - } - - TizenResult SetOperation(const std::string& operation) { - return app_control_set_operation(app_control_, operation.c_str()); - } - - TizenResult SendLauchRequest() { - return app_control_send_launch_request(app_control_, nullptr, nullptr); - } - - private: - app_control_h app_control_{nullptr}; -}; - -class PackageName { - public: - PackageName() { Init(); } - - ~PackageName() {} - - operator std::string() const { return package_name_; } - - private: - void Init() { - char* id = nullptr; - std::string app_id; - if (app_get_id(&id) != 0) { - return; - } - - app_id = id; - free(id); - - char* package_name = nullptr; - package_info_h package_info = nullptr; - - package_info_create(app_id.c_str(), &package_info); - - if (package_info_get_package(package_info, &package_name) != 0) { - return; - } - - package_info_destroy(package_info); - package_name_ = package_name; - - free(package_name); - } - - std::string package_name_; -}; - -} // namespace - -TizenResult Setting::LaunchAppSetting() { - PackageName name; - AppControl app_ctrl; - - app_ctrl.SetAppId("com.samsung.clocksetting.apps"); - app_ctrl.AddExtraData("pkgId", name); - - return app_ctrl.SendLauchRequest(); -} - -TizenResult Setting::LaunchLocationSetting() { - AppControl app_ctrl; - - app_ctrl.SetAppId("com.samsung.setting-location"); - app_ctrl.SetOperation( - "http://tizen.org/appcontrol/operation/configure/location"); - - return app_ctrl.SendLauchRequest(); -} diff --git a/packages/geolocator/tizen/src/setting.h b/packages/geolocator/tizen/src/setting.h deleted file mode 100644 index c9bbd6e1c..000000000 --- a/packages/geolocator/tizen/src/setting.h +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -#ifndef SETTING_H_ -#define SETTING_H_ - -#include "tizen_result.h" - -namespace Setting { - -TizenResult LaunchAppSetting(); -TizenResult LaunchLocationSetting(); - -}; // namespace Setting - -#endif diff --git a/packages/geolocator/tizen/src/tizen_result.h b/packages/geolocator/tizen/src/tizen_result.h deleted file mode 100644 index 1841320b6..000000000 --- a/packages/geolocator/tizen/src/tizen_result.h +++ /dev/null @@ -1,24 +0,0 @@ -// 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. - -#ifndef TIZEN_RESULT_H_ -#define TIZEN_RESULT_H_ - -#include - -#include - -struct TizenResult { - TizenResult() : error_code(TIZEN_ERROR_NONE){}; - TizenResult(int code) : error_code(code) {} - - // Returns false on error. - operator bool() const { return (error_code == TIZEN_ERROR_NONE); } - - std::string message() { return get_error_message(error_code); } - - int error_code = TIZEN_ERROR_NONE; -}; - -#endif // TIZEN_RESULT_H_