summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packaging/webapi-plugins.spec173
-rw-r--r--src/account/account.gyp1
-rwxr-xr-xsrc/account/account_api.js58
-rw-r--r--src/alarm/alarm.gyp2
-rwxr-xr-xsrc/alarm/alarm_api.js12
-rw-r--r--src/alarm/alarm_manager.cc8
-rwxr-xr-xsrc/application/application_api.js10
-rw-r--r--src/application/application_manager.cc421
-rw-r--r--src/application/application_manager.h3
-rw-r--r--src/application/application_utils.cc298
-rw-r--r--src/application/application_utils.h2
-rwxr-xr-xsrc/archive/archive_api.js77
-rw-r--r--src/archive/archive_file.cc6
-rw-r--r--src/archive/archive_instance.cc26
-rw-r--r--src/archive/archive_instance.h2
-rw-r--r--src/archive/filesystem_node.cc7
-rw-r--r--src/archive/un_zip.cc2
-rw-r--r--src/archive/un_zip_extract_request.cc2
-rw-r--r--src/archive/zip_add_request.cc8
-rw-r--r--src/badge/badge_manager.cc4
-rwxr-xr-xsrc/bluetooth/bluetooth_api.js55
-rw-r--r--src/calendar/calendar_item.cc12
-rwxr-xr-xsrc/calendar/js/calendar.js4
-rw-r--r--src/calendar/js/calendar_item.js23
-rw-r--r--src/callhistory/callhistory.cc8
-rw-r--r--src/common/GDBus/proxy.cpp2
-rw-r--r--src/common/common.gyp4
-rw-r--r--src/common/common.gypi1
-rw-r--r--src/common/extension.cc23
-rw-r--r--src/common/extension.h2
-rw-r--r--src/common/logger.h33
-rw-r--r--src/common/picojson.h873
-rw-r--r--src/common/platform_enum.h81
-rw-r--r--src/common/task-queue.cpp58
-rw-r--r--src/common/task-queue.h152
-rw-r--r--src/common/tools.cc48
-rw-r--r--src/common/tools.h28
-rw-r--r--src/common/worker.cc100
-rw-r--r--src/common/worker.h80
-rw-r--r--src/contact/contact_instance.cc71
-rw-r--r--src/contact/contact_util.cc18
-rwxr-xr-xsrc/contact/js/contact.js4
-rwxr-xr-xsrc/contact/js/person.js2
-rw-r--r--src/content/content_instance.cc138
-rw-r--r--src/content/content_manager.cc91
-rw-r--r--src/content/content_manager.h12
-rwxr-xr-xsrc/content/js/datatypes.js4
-rwxr-xr-xsrc/content/js/manager.js10
-rwxr-xr-xsrc/content/js/playlist.js12
-rwxr-xr-xsrc/datacontrol/datacontrol_api.js10
-rw-r--r--src/download/download_instance.cc5
-rw-r--r--src/exif/exif_api.js52
-rw-r--r--src/exif/exif_information.cc6
-rw-r--r--src/exif/exif_instance.cc26
-rw-r--r--src/exif/exif_tag_saver.cc2
-rw-r--r--src/exif/get_exif_info.cc10
-rw-r--r--src/exif/jpeg_file.cc107
-rwxr-xr-xsrc/feedback/feedback_api.js69
-rw-r--r--src/feedback/feedback_manager.cc6
-rwxr-xr-xsrc/filesystem/filesystem_api.js1
-rw-r--r--src/filesystem/filesystem_instance.cc1586
-rw-r--r--src/filesystem/filesystem_instance.h90
-rw-r--r--src/filesystem/filesystem_manager.cc5
-rw-r--r--src/filesystem/filesystem_manager.h2
-rw-r--r--src/filesystem/filesystem_stat.cc3
-rwxr-xr-xsrc/filesystem/filesystem_stat.h2
-rw-r--r--src/filesystem/filesystem_utils.cc354
-rw-r--r--src/filesystem/filesystem_utils.h120
-rw-r--r--src/filesystem/js/common.js67
-rw-r--r--src/filesystem/js/file.js67
-rw-r--r--src/filesystem/js/file_handle.js802
-rw-r--r--src/filesystem/js/file_stream.js125
-rw-r--r--[-rwxr-xr-x]src/filesystem/js/file_system_manager.js599
-rwxr-xr-xsrc/humanactivitymonitor/humanactivitymonitor_api.js176
-rw-r--r--src/humanactivitymonitor/humanactivitymonitor_extension.cc3
-rw-r--r--src/humanactivitymonitor/humanactivitymonitor_manager.cc58
-rw-r--r--src/inputdevice/inputdevice_api.js8
-rw-r--r--src/iotcon/iotcon_instance.cc2
-rwxr-xr-xsrc/mediacontroller/mediacontroller_api.js44
-rw-r--r--src/mediacontroller/mediacontroller_client.cc177
-rw-r--r--src/mediacontroller/mediacontroller_client.h8
-rw-r--r--src/mediacontroller/mediacontroller_instance.cc74
-rw-r--r--src/mediacontroller/mediacontroller_server.cc113
-rw-r--r--src/mediacontroller/mediacontroller_server.h10
-rw-r--r--src/mediacontroller/mediacontroller_types.cc199
-rw-r--r--src/mediacontroller/mediacontroller_types.h38
-rwxr-xr-xsrc/messageport/messageport_api.js175
-rw-r--r--src/messageport/messageport_instance.cc39
-rw-r--r--src/messaging/DBus/MessageProxy.h1
-rw-r--r--src/messaging/MsgCommon/AttributeRangeFilter.h1
-rw-r--r--src/messaging/conversations_change_callback.cc14
-rw-r--r--src/messaging/email_manager.cc165
-rw-r--r--src/messaging/folders_change_callback.cc12
-rw-r--r--src/messaging/message.cc34
-rw-r--r--src/messaging/message.h1
-rw-r--r--src/messaging/messages_change_callback.cc16
-rw-r--r--src/messaging/messaging.gyp1
-rwxr-xr-xsrc/messaging/messaging_api.js26
-rw-r--r--src/messaging/messaging_instance.cc13
-rw-r--r--src/messaging/messaging_util.cc3
-rw-r--r--src/messaging/short_message_manager.cc36
-rw-r--r--src/networkbearerselection/networkbearerselection_instance.cc16
-rw-r--r--src/networkbearerselection/networkbearerselection_manager.cc53
-rw-r--r--src/nfc/nfc_adapter.cc8
-rw-r--r--src/nfc/nfc_api.js6
-rw-r--r--src/nfc/nfc_util.cc4
-rw-r--r--src/notification/common_notification.cc5
-rw-r--r--src/package/package_api.js303
-rw-r--r--src/package/package_instance.cc56
-rw-r--r--src/package/package_instance.h3
-rwxr-xr-xsrc/power/power_api.js12
-rw-r--r--src/ppm/ppm_api.js65
-rw-r--r--src/ppm/ppm_instance.cc109
-rw-r--r--src/ppm/ppm_instance.h5
-rw-r--r--src/preference/preference_manager.cc5
-rw-r--r--src/push/push_api.js16
-rw-r--r--src/radio/radio.gyp3
-rw-r--r--src/radio/radio_manager.cc187
-rw-r--r--src/radio/radio_manager.h6
-rw-r--r--src/secureelement/secureelement_instance.cc11
-rwxr-xr-xsrc/sensor/sensor_api.js39
-rw-r--r--src/sensor/sensor_service.cc1
-rw-r--r--src/sound/sound.gyp3
-rw-r--r--src/sound/sound_api.js29
-rw-r--r--src/sound/sound_instance.cc5
-rw-r--r--src/sound/sound_instance.h3
-rw-r--r--src/sound/sound_manager.cc31
-rw-r--r--src/systeminfo/systeminfo-utils.cpp31
-rw-r--r--src/systeminfo/systeminfo.gyp23
-rw-r--r--src/systeminfo/systeminfo_api.js12
-rw-r--r--src/systeminfo/systeminfo_properties_manager.cc2
-rw-r--r--src/systeminfo/systeminfo_sim_details_manager.cc14
-rw-r--r--src/systemsetting/systemsetting.gyp1
-rw-r--r--src/systemsetting/systemsetting_instance.cc20
-rw-r--r--src/time/time_api.js16
-rw-r--r--src/tizen/tizen_api.js6
-rwxr-xr-xsrc/tvinputdevice/tvinputdevice_api.js8
-rw-r--r--src/utils/utils_api.js51
-rw-r--r--src/utils/utils_extension.cc1
-rw-r--r--src/utils/utils_instance.h4
-rw-r--r--src/widgetservice/widgetservice_api.js4
-rw-r--r--src/widgetservice/widgetservice_instance.cc16
142 files changed, 7282 insertions, 2545 deletions
diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec
index 75c40e0e..b555e027 100644
--- a/packaging/webapi-plugins.spec
+++ b/packaging/webapi-plugins.spec
@@ -8,7 +8,7 @@
%define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions}
Name: webapi-plugins
-Version: 2.34
+Version: 2.39
Release: 0
License: Apache-2.0 and BSD-3-Clause and MIT
Group: Development/Libraries
@@ -30,6 +30,7 @@ Source0: %{name}-%{version}.tar.gz
%define tizen_common_feature_bluetooth_support 1
%define tizen_common_feature_bookmark_support 0
%define tizen_common_feature_calendar_support 0
+%define tizen_common_feature_callhistory_support 0
%define tizen_common_feature_contact_support 0
%define tizen_common_feature_content_support 1
%define tizen_common_feature_datacontrol_support 0
@@ -40,19 +41,22 @@ Source0: %{name}-%{version}.tar.gz
%define tizen_common_feature_filesystem_support 1
%define tizen_common_feature_fm_radio_support 0
%define tizen_common_feature_ham_support 0
+%define tizen_common_feature_inputdevice_support 0
%define tizen_common_feature_iotcon_support 0
-%define tizen_common_feature_location_batch 0
%define tizen_common_feature_key_manager_support 0
+%define tizen_common_feature_location_batch 0
%define tizen_common_feature_media_controller_support 0
%define tizen_common_feature_media_key_support 0
%define tizen_common_feature_message_port_support 1
%define tizen_common_feature_messaging_support 0
-%define tizen_common_feature_nfc_emulation_support 0
+%define tizen_common_feature_nbs_support 0
%define tizen_common_feature_nfc_support 0
+%define tizen_common_feature_nfc_emulation_support 0
%define tizen_common_feature_notification_support 0
%define tizen_common_feature_package_support 1
%define tizen_common_feature_player_util_support 0
%define tizen_common_feature_power_support 0
+%define tizen_common_feature_ppm_support 0
%define tizen_common_feature_preference_support 0
%define tizen_common_feature_push_support 0
%define tizen_common_feature_se_support 0
@@ -62,16 +66,11 @@ Source0: %{name}-%{version}.tar.gz
%define tizen_common_feature_system_setting_support 0
%define tizen_common_feature_telephony_support 0
%define tizen_common_feature_time_support 1
-%define tizen_common_feature_web_setting_support 0
-%define tizen_common_feature_widget_service_support 0
-%define tizen_common_feature_wi_fi_support 1
-%define tizen_common_feature_inputdevice_support 0
-%define tizen_common_feature_callhistory_support 0
-%define tizen_common_feature_nbs_support 0
%define tizen_common_feature_tvinputdevice_support 0
%define tizen_common_feature_voicecontrol_support 0
-%define tizen_common_feature_ppm_support 0
-
+%define tizen_common_feature_web_setting_support 0
+%define tizen_common_feature_wi_fi_support 1
+%define tizen_common_feature_widget_service_support 0
####################################################################
# Mobile Profile : TM1(32bit), Redwood(SM-Z910F), KIRAN(Z130H) #
@@ -105,24 +104,21 @@ Source0: %{name}-%{version}.tar.gz
%endif
%define tizen_mobile_feature_ham_support 0
-
+%define tizen_mobile_feature_inputdevice_support 1
%define tizen_mobile_feature_iotcon_support 1
-%define tizen_mobile_feature_location_batch 0
%define tizen_mobile_feature_key_manager_support 1
+%define tizen_mobile_feature_location_batch 0
%define tizen_mobile_feature_media_controller_support 1
-
%define tizen_mobile_feature_media_key_support 1
-
%define tizen_mobile_feature_message_port_support 1
%define tizen_mobile_feature_messaging_support 1
-
-%define tizen_mobile_feature_nfc_emulation_support 0
%define tizen_mobile_feature_nfc_support 0
-
+%define tizen_mobile_feature_nfc_emulation_support 0
%define tizen_mobile_feature_notification_support 1
%define tizen_mobile_feature_package_support 1
%define tizen_mobile_feature_player_util_support 1
%define tizen_mobile_feature_power_support 1
+%define tizen_mobile_feature_ppm_support 1
%define tizen_mobile_feature_preference_support 1
%define tizen_mobile_feature_push_support 1
@@ -150,17 +146,33 @@ Source0: %{name}-%{version}.tar.gz
%endif
%define tizen_mobile_feature_time_support 1
+%define tizen_mobile_feature_tvinputdevice_support 0
+%define tizen_mobile_feature_voicecontrol_support 1
%define tizen_mobile_feature_web_setting_support 1
+%define tizen_mobile_feature_wi_fi_support 1
%define tizen_mobile_feature_widget_service_support 1
-%define tizen_mobile_feature_wi_fi_support 1
+## Mobile emulator
-%define tizen_mobile_feature_inputdevice_support 1
+%define tizen_mobile_emulator_feature_bluetooth_support 0
-%define tizen_mobile_feature_tvinputdevice_support 0
+# FM radio feature
+%define tizen_mobile_emulator_feature_fm_radio_support 1
-%define tizen_mobile_feature_voicecontrol_support 1
-%define tizen_mobile_feature_ppm_support 1
+%define tizen_mobile_emulator_feature_ham_support 1
+%define tizen_mobile_emulator_feature_media_key_support 0
+%define tizen_mobile_emulator_feature_nfc_support 1
+%define tizen_mobile_emulator_feature_nfc_emulation_support 0
+
+# secure element feature
+%define tizen_mobile_emulator_feature_se_support 0
+
+# telephony feature
+%define tizen_mobile_emulator_feature_telephony_support 1
+%define tizen_mobile_emulator_feature_callhistory_support 1
+%define tizen_mobile_emulator_feature_nbs_support 1
+
+%define tizen_mobile_emulator_feature_wi_fi_support 0
####################################################################
# Wearable Profile : B2 / TW2 #
@@ -198,22 +210,24 @@ Source0: %{name}-%{version}.tar.gz
%define tizen_wearable_feature_filesystem_support 1
%define tizen_wearable_feature_fm_radio_support 0
%define tizen_wearable_feature_ham_support 1
+%define tizen_wearable_feature_inputdevice_support 1
%define tizen_wearable_feature_iotcon_support 1
+%define tizen_wearable_feature_key_manager_support 1
%define tizen_wearable_feature_location_batch 0
%define tizen_wearable_feature_media_controller_support 1
# MediayKey API is optional in Tizen Wearable Profile.
# tizen.org/feature/network.bluetooth.audio.media is required for MediayKey API
%define tizen_wearable_feature_media_key_support 1
-%define tizen_wearable_feature_key_manager_support 1
%define tizen_wearable_feature_message_port_support 1
%define tizen_wearable_feature_messaging_support 0
-%define tizen_wearable_feature_nfc_emulation_support 0
%define tizen_wearable_feature_nfc_support 1
+%define tizen_wearable_feature_nfc_emulation_support 0
%define tizen_wearable_feature_notification_support 1
%define tizen_wearable_feature_package_support 1
%define tizen_wearable_feature_player_util_support 1
%define tizen_wearable_feature_power_support 1
+%define tizen_wearable_feature_ppm_support 1
%define tizen_wearable_feature_preference_support 1
%define tizen_wearable_feature_push_support 1
%define tizen_wearable_feature_se_support 1
@@ -230,15 +244,29 @@ Source0: %{name}-%{version}.tar.gz
%define tizen_wearable_feature_nbs_support 0
%define tizen_wearable_feature_time_support 1
+%define tizen_wearable_feature_tvinputdevice_support 0
+%define tizen_wearable_feature_voicecontrol_support 1
%define tizen_wearable_feature_web_setting_support 0
-%define tizen_wearable_feature_widget_service_support 1
%define tizen_wearable_feature_wi_fi_support 1
-%define tizen_wearable_feature_inputdevice_support 1
-%define tizen_wearable_feature_tvinputdevice_support 0
+%define tizen_wearable_feature_widget_service_support 1
-%define tizen_wearable_feature_voicecontrol_support 1
-%define tizen_wearable_feature_ppm_support 1
+## Wearable emulator
+
+%define tizen_wearable_emulator_feature_bluetooth_support 0
+
+# MediayKey API is optional in Tizen Wearable Profile.
+# tizen.org/feature/network.bluetooth.audio.media is required for MediayKey API
+%define tizen_wearable_emulator_feature_media_key_support 0
+
+#- telephony related APIs
+# CallHistory API is optional in Tizen Wearable Profile.
+# NetworkBearerSelection API is optional in Tizen Wearable Profile.
+%define tizen_wearable_emulator_feature_telephony_support 1
+%define tizen_wearable_emulator_feature_callhistory_support 1
+%define tizen_wearable_emulator_feature_nbs_support 1
+%define tizen_wearable_emulator_feature_se_support 0
+%define tizen_wearable_emulator_feature_sensor_support 1
####################################################################
# TV Profile #
@@ -246,7 +274,7 @@ Source0: %{name}-%{version}.tar.gz
%define tizen_tv_privilege_engine CYNARA
-%define tizen_tv_feature_account_support 0
+%define tizen_tv_feature_account_support 1
%define tizen_tv_feature_alarm_support 1
%define tizen_tv_feature_app_control_settings_support 0
%define tizen_tv_feature_application_support 1
@@ -266,19 +294,21 @@ Source0: %{name}-%{version}.tar.gz
%define tizen_tv_feature_filesystem_support 1
%define tizen_tv_feature_fm_radio_support 0
%define tizen_tv_feature_ham_support 0
+%define tizen_tv_feature_inputdevice_support 0
%define tizen_tv_feature_iotcon_support 1
%define tizen_tv_feature_key_manager_support 1
-%define tizen_tv_feature_media_controller_support 0
+%define tizen_tv_feature_media_controller_support 1
%define tizen_tv_feature_media_key_support 0
%define tizen_tv_feature_message_port_support 1
%define tizen_tv_feature_messaging_support 0
%define tizen_tv_feature_nbs_support 0
-%define tizen_tv_feature_nfc_emulation_support 0
%define tizen_tv_feature_nfc_support 0
+%define tizen_tv_feature_nfc_emulation_support 0
%define tizen_tv_feature_notification_support 0
%define tizen_tv_feature_package_support 1
%define tizen_tv_feature_player_util_support 0
%define tizen_tv_feature_power_support 0
+%define tizen_tv_feature_ppm_support 0
%define tizen_tv_feature_preference_support 0
%define tizen_tv_feature_push_support 1
%define tizen_tv_feature_se_support 0
@@ -288,13 +318,11 @@ Source0: %{name}-%{version}.tar.gz
%define tizen_tv_feature_system_setting_support 0
%define tizen_tv_feature_telephony_support 0
%define tizen_tv_feature_time_support 1
-%define tizen_tv_feature_web_setting_support 1
-%define tizen_tv_feature_widget_service_support 0
-%define tizen_tv_feature_wi_fi_support 1
-%define tizen_tv_feature_inputdevice_support 0
%define tizen_tv_feature_tvinputdevice_support 1
%define tizen_tv_feature_voicecontrol_support 1
-%define tizen_tv_feature_ppm_support 0
+%define tizen_tv_feature_web_setting_support 1
+%define tizen_tv_feature_wi_fi_support 1
+%define tizen_tv_feature_widget_service_support 0
# common, or "unified (undefined)"
%define unified_build 1
@@ -453,7 +481,7 @@ BuildRequires: pkgconfig(capi-data-control)
BuildRequires: pkgconfig(capi-web-url-download)
%endif
-%if "%{?tizen_feature_ham_support}" == "1" || "%{?unified_build}" == "1"
+%if "%{?tizen_feature_ham_support}" == "1" || "%{?unified_build}" == "1" || "%{?tizen_mobile_emulator_feature_ham_support}" == "1"
BuildRequires: pkgconfig(motion)
BuildRequires: pkgconfig(capi-system-sensor)
BuildRequires: pkgconfig(capi-location-manager)
@@ -490,7 +518,6 @@ BuildRequires: pkgconfig(ecore-file)
BuildRequires: pkgconfig(email-service)
BuildRequires: pkgconfig(msg-service)
BuildRequires: pkgconfig(db-util)
-BuildRequires: pkgconfig(dbus-glib-1)
%endif
%if "%{?tizen_feature_badge_support}" == "1" || "%{?unified_build}" == "1"
@@ -505,7 +532,7 @@ BuildRequires: pkgconfig(calendar-service2)
BuildRequires: pkgconfig(contacts-service2)
%endif
-%if "%{?tizen_feature_callhistory_support}" == "1" || "%{?unified_build}" == "1"
+%if "%{?tizen_feature_callhistory_support}" == "1" || "%{?unified_build}" == "1" || "%{?tizen_mobile_emulator_feature_callhistory_support}" == "1" || "%{?tizen_wearable_emulator_feature_callhistory_support}" == "1"
BuildRequires: pkgconfig(contacts-service2)
%endif
@@ -513,12 +540,12 @@ BuildRequires: pkgconfig(contacts-service2)
BuildRequires: pkgconfig(libexif)
%endif
-%if "%{?tizen_feature_nfc_support}" == "1" || "%{?unified_build}" == "1"
+%if "%{?tizen_feature_nfc_support}" == "1" || "%{?unified_build}" == "1" || "%{?tizen_mobile_emulator_feature_nfc_support}" == "1"
BuildRequires: pkgconfig(capi-network-nfc)
BuildRequires: pkgconfig(capi-appfw-app-control)
%endif
-%if "%{?tizen_feature_fm_radio_support}" == "1" || "%{?unified_build}" == "1"
+%if "%{?tizen_feature_fm_radio_support}" == "1" || "%{?unified_build}" == "1" || "%{?tizen_mobile_emulator_feature_fm_radio_support}" == "1"
BuildRequires: pkgconfig(capi-media-radio)
%endif
@@ -547,7 +574,7 @@ BuildRequires: pkgconfig(capi-appfw-preference)
BuildRequires: pkgconfig(capi-media-sound-manager)
%endif
-%if "%{?tizen_feature_sensor_support}" == "1" || "%{?unified_build}" == "1"
+%if "%{?tizen_feature_sensor_support}" == "1" || "%{?unified_build}" == "1" || "%{?tizen_wearable_emulator_feature_sensor_support}" == "1"
BuildRequires: pkgconfig(capi-system-sensor)
%endif
@@ -720,33 +747,30 @@ GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ppm_support=%{?tizen_mobile_feature_pp
ninja -C out/Default %{?_smp_mflags}
pushd out
mv Default bin_mobile
-%if "%{?profile}" == "mobile"
-ln -sf bin_mobile Default
-%endif
popd
# mobile-extension-emulator
%ifarch %{ix86} x86_64
-%define tizen_mobile_feature_bluetooth_support 0
+%define tizen_mobile_feature_bluetooth_support %{?tizen_mobile_emulator_feature_bluetooth_support}
# FM radio feature
-%define tizen_mobile_feature_fm_radio_support 1
+%define tizen_mobile_feature_fm_radio_support %{?tizen_mobile_emulator_feature_fm_radio_support}
-%define tizen_mobile_feature_ham_support 1
-%define tizen_mobile_feature_media_key_support 0
-%define tizen_mobile_feature_nfc_emulation_support 0
-%define tizen_mobile_feature_nfc_support 1
+%define tizen_mobile_feature_ham_support %{?tizen_mobile_emulator_feature_ham_support}
+%define tizen_mobile_feature_media_key_support %{?tizen_mobile_emulator_feature_media_key_support}
+%define tizen_mobile_feature_nfc_emulation_support %{?tizen_mobile_emulator_feature_nfc_emulation_support}
+%define tizen_mobile_feature_nfc_support %{?tizen_mobile_emulator_feature_nfc_support}
# secure element feature
-%define tizen_mobile_feature_se_support 0
+%define tizen_mobile_feature_se_support %{?tizen_mobile_emulator_feature_se_support}
# telephony feature
-%define tizen_mobile_feature_telephony_support 1
-%define tizen_mobile_feature_callhistory_support 1
-%define tizen_mobile_feature_nbs_support 1
+%define tizen_mobile_feature_telephony_support %{?tizen_mobile_emulator_feature_telephony_support}
+%define tizen_mobile_feature_callhistory_support %{?tizen_mobile_emulator_feature_callhistory_support}
+%define tizen_mobile_feature_nbs_support %{?tizen_mobile_emulator_feature_nbs_support}
-%define tizen_mobile_feature_wi_fi_support 0
+%define tizen_mobile_feature_wi_fi_support %{?tizen_mobile_emulator_feature_wi_fi_support}
GYP_OPTIONS="--depth=. -Dtizen=1 -Dextension_build_type=Debug -Dextension_host_os=mobile -Dprivilege_engine=%{tizen_mobile_privilege_engine}"
GYP_OPTIONS="$GYP_OPTIONS -Ddisplay_type=%{display_type}"
@@ -810,11 +834,15 @@ GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ppm_support=%{?tizen_mobile_feature_pp
ninja -C out/Default %{?_smp_mflags}
pushd out
mv Default bin_mobile_emulator
+popd
+%endif # mobile-extension-emulator
+
+pushd out
%if "%{?profile}" == "mobile"
-ln -sf bin_mobile_emulator Default
+ln -sf bin_mobile Default
%endif
popd
-%endif # mobile-extension-emulator
+
%endif # MOBILE
%if "%{?unified_build}" == "1" || "%{?profile}" == "wearable"
@@ -881,28 +909,25 @@ GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ppm_support=%{?tizen_wearable_feature_
ninja -C out/Default %{?_smp_mflags}
pushd out
mv Default bin_wearable
-%if "%{?profile}" == "wearable"
-ln -sf bin_wearable Default
-%endif
popd
# wearable-extension-emulator
%ifarch %{ix86} x86_64
-%define tizen_wearable_feature_bluetooth_support 0
+%define tizen_wearable_feature_bluetooth_support %{?tizen_wearable_emulator_feature_bluetooth_support}
# MediayKey API is optional in Tizen Wearable Profile.
# tizen.org/feature/network.bluetooth.audio.media is required for MediayKey API
-%define tizen_wearable_feature_media_key_support 0
+%define tizen_wearable_feature_media_key_support %{?tizen_wearable_emulator_feature_media_key_support}
#- telephony related APIs
# CallHistory API is optional in Tizen Wearable Profile.
# NetworkBearerSelection API is optional in Tizen Wearable Profile.
-%define tizen_wearable_feature_se_support 0
-%define tizen_wearable_feature_telephony_support 1
-%define tizen_wearable_feature_callhistory_support 1
-%define tizen_wearable_feature_nbs_support 1
-%define tizen_wearable_feature_sensor_support 1
+%define tizen_wearable_feature_se_support %{?tizen_wearable_emulator_feature_se_support}
+%define tizen_wearable_feature_telephony_support %{?tizen_wearable_emulator_feature_telephony_support}
+%define tizen_wearable_feature_callhistory_support %{?tizen_wearable_emulator_feature_callhistory_support}
+%define tizen_wearable_feature_nbs_support %{?tizen_wearable_emulator_feature_nbs_support}
+%define tizen_wearable_feature_sensor_support %{?tizen_wearable_emulator_feature_sensor_support}
GYP_OPTIONS="--depth=. -Dtizen=1 -Dextension_build_type=Debug -Dextension_host_os=wearable -Dprivilege_engine=%{tizen_wearable_privilege_engine}"
GYP_OPTIONS="$GYP_OPTIONS -Ddisplay_type=%{display_type}"
@@ -966,11 +991,15 @@ GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ppm_support=%{?tizen_wearable_feature_
ninja -C out/Default %{?_smp_mflags}
pushd out
mv Default bin_wearable_emulator
+popd
+%endif # wearable-extension-emulator
+
+pushd out
%if "%{?profile}" == "wearable"
-ln -sf bin_wearable_emulator Default
+ln -sf bin_wearable Default
%endif
popd
-%endif # wearable-extension-emulator
+
%endif # WEARABLE
%if "%{?unified_build}" == "1" || "%{?profile}" == "tv"
diff --git a/src/account/account.gyp b/src/account/account.gyp
index 272a0435..3fb0e3ed 100644
--- a/src/account/account.gyp
+++ b/src/account/account.gyp
@@ -22,7 +22,6 @@
['tizen == 1', {
'variables': {
'packages': [
- 'capi-appfw-package-manager',
'accounts-svc',
]
},
diff --git a/src/account/account_api.js b/src/account/account_api.js
index 5c7c8832..db4eb6f3 100755
--- a/src/account/account_api.js
+++ b/src/account/account_api.js
@@ -39,26 +39,10 @@ function AccountProvider(data) {
Object.freeze(internal_);
Object.defineProperties(this, {
- applicationId: {
- enumerable: true,
- writable: false,
- value: data.applicationId
- },
- displayName: {
- enumerable: true,
- writable: false,
- value: data.displayName
- },
- iconUri: {
- enumerable: true,
- writable: false,
- value: data.iconUri
- },
- smallIconUri: {
- enumerable: true,
- writable: false,
- value: data.smallIconUri
- },
+ applicationId: { enumerable: true, writable: false, value: data.applicationId },
+ displayName: { enumerable: true, writable: false, value: data.displayName },
+ iconUri: { enumerable: true, writable: false, value: data.iconUri },
+ smallIconUri: { enumerable: true, writable: false, value: data.smallIconUri },
capabilities: {
enumerable: true,
set: function() {},
@@ -77,11 +61,7 @@ function AccountProvider(data) {
function Account() {
validator_.isConstructorCall(this, tizen.Account);
var args = validator_.validateArgs(arguments, [
- {
- name: 'provider',
- type: types_.PLATFORM_OBJECT,
- values: AccountProvider
- },
+ { name: 'provider', type: types_.PLATFORM_OBJECT, values: AccountProvider },
{
name: 'accountInitDict',
type: types_.DICTIONARY,
@@ -291,18 +271,8 @@ AccountManager.prototype.getAccounts = function() {
optional: false,
nullable: false
},
- {
- name: 'errorCallback',
- type: types_.FUNCTION,
- optional: true,
- nullable: true
- },
- {
- name: 'applicationId',
- type: types_.STRING,
- optional: true,
- nullable: true
- }
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
+ { name: 'applicationId', type: types_.STRING, optional: true, nullable: true }
]);
var result = native_.call(
@@ -361,18 +331,8 @@ AccountManager.prototype.getProviders = function() {
optional: false,
nullable: false
},
- {
- name: 'errorCallback',
- type: types_.FUNCTION,
- optional: true,
- nullable: true
- },
- {
- name: 'capability',
- type: types_.STRING,
- optional: true,
- nullable: true
- }
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
+ { name: 'capability', type: types_.STRING, optional: true, nullable: true }
]);
var result = native_.call(
diff --git a/src/alarm/alarm.gyp b/src/alarm/alarm.gyp
index 6a5739e9..df129e03 100644
--- a/src/alarm/alarm.gyp
+++ b/src/alarm/alarm.gyp
@@ -26,7 +26,9 @@
'packages': [
'capi-appfw-alarm',
'capi-appfw-app-control',
+ 'alarm-service',
'capi-appfw-application',
+ 'notification',
]
},
}],
diff --git a/src/alarm/alarm_api.js b/src/alarm/alarm_api.js
index eb668868..98b4c7be 100755
--- a/src/alarm/alarm_api.js
+++ b/src/alarm/alarm_api.js
@@ -446,8 +446,8 @@ tizen.AlarmAbsolute = function(date, second, internal) {
if (_warningLogs.enableLog && isAlarmAbsolutePeriodDeprecated) {
privUtils_.warn(
'This Constructor is deprecated since Tizen 4.0.' +
- ' Please consider using other constructors or ' +
- 'other type of an alarm.'
+ ' Please consider using other constructors or other ' +
+ 'type of an alarm.'
);
}
}
@@ -476,8 +476,8 @@ tizen.AlarmAbsolute = function(date, second, internal) {
if (_warningLogs.enableLog && isAlarmAbsolutePeriodDeprecated) {
privUtils_.warn(
'Since Tizen 4.0 constructor AlarmAbsolute(Date date, ' +
- 'long period) is deprecated, thus period attribute should ' +
- 'not be used.'
+ 'long period) is deprecated, thus period attribute ' +
+ 'should not be used.'
);
}
return m_period;
@@ -486,8 +486,8 @@ tizen.AlarmAbsolute = function(date, second, internal) {
if (_warningLogs.enableLog && isAlarmAbsolutePeriodDeprecated) {
privUtils_.warn(
'Since Tizen 4.0 constructor AlarmAbsolute(Date date, ' +
- 'long period) is deprecated, thus period attribute should ' +
- 'not be used.'
+ 'long period) is deprecated, thus period attribute ' +
+ 'should not be used.'
);
}
diff --git a/src/alarm/alarm_manager.cc b/src/alarm/alarm_manager.cc
index 7a27dfcc..bcc74e04 100644
--- a/src/alarm/alarm_manager.cc
+++ b/src/alarm/alarm_manager.cc
@@ -143,7 +143,8 @@ void AlarmManager::Add(const picojson::value& args, picojson::object& out) {
}
std::string delay_str = std::to_string(delay);
- int ret_app = app_control_add_extra_data(app_control, kAlarmRelativeDelayKey, delay_str.c_str());
+ int ret_app =
+ app_control_add_extra_data(app_control, kAlarmRelativeDelayKey, delay_str.c_str());
if (APP_CONTROL_ERROR_NONE != ret_app) {
LogAndReportError(
PlatformResult(ErrorCode::UNKNOWN_ERR, "Fail to add data from app_control."), &out,
@@ -631,8 +632,9 @@ PlatformResult AlarmManager::GetAlarm(int id, picojson::object& obj) {
int ret_app = app_control_get_extra_data(app_control, kAlarmRelativeDelayKey, &delay_string);
if (APP_CONTROL_ERROR_NONE != ret_app) {
- return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Failed to get data.",
- ("Failed to get data: %d (%s)", ret_app, get_error_message(ret_app)));
+ return LogAndCreateResult(
+ ErrorCode::NOT_FOUND_ERR, "Failed to get data.",
+ ("Failed to get data: %d (%s)", ret_app, get_error_message(ret_app)));
}
obj.insert(std::make_pair("type", picojson::value(kAlarmRelative)));
diff --git a/src/application/application_api.js b/src/application/application_api.js
index 70586eef..8855b06b 100755
--- a/src/application/application_api.js
+++ b/src/application/application_api.js
@@ -753,8 +753,8 @@ var applicationEventListener = new ListenerManager(native, APPLICATION_EVENT_LIS
ApplicationManager.prototype.addAppInfoEventListener = function() {
privUtils_.warn(
- 'DEPRECATION WARNING: addAppInfoEventListener() is deprecated ' +
- 'and will be removed from next release. ' +
+ 'DEPRECATION WARNING: addAppInfoEventListener() is deprecated and will ' +
+ 'be removed from next release. ' +
'Use tizen.package.setPackageInfoEventListener() instead.'
);
@@ -771,8 +771,8 @@ ApplicationManager.prototype.addAppInfoEventListener = function() {
ApplicationManager.prototype.removeAppInfoEventListener = function() {
privUtils_.warn(
- 'DEPRECATION WARNING: removeAppInfoEventListener() is deprecated ' +
- 'and will be removed from next release. ' +
+ 'DEPRECATION WARNING: removeAppInfoEventListener() is deprecated and will ' +
+ 'be removed from next release. ' +
'Use tizen.package.unsetPackageInfoEventListener() instead.'
);
@@ -1003,8 +1003,8 @@ Application.prototype.addEventListener = function(event, callback) {
event_listeners_[eventName][id](eventInfo, msg.data);
} else {
delete msg.name;
- //TODO: type should come from native site
msg.type = parsedName[2];
+ //TODO: type should come from native site
eventInfo.name = parsedName[2].toUpperCase();
event_listeners_[eventName][id](eventInfo, msg);
}
diff --git a/src/application/application_manager.cc b/src/application/application_manager.cc
index 69e2a559..840faafe 100644
--- a/src/application/application_manager.cc
+++ b/src/application/application_manager.cc
@@ -16,6 +16,7 @@
#include "application_manager.h"
+#include <glib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <type_traits>
@@ -213,7 +214,7 @@ class TerminateHandler {
return; \
}
-void ApplicationManager::AsyncResponse(PlatformResult& result,
+void ApplicationManager::AsyncResponse(const PlatformResult& result,
std::shared_ptr<picojson::value>* response) {
ScopeLogger();
LogAndReportError(result, &(*response)->get<picojson::object>());
@@ -375,82 +376,52 @@ void ApplicationManager::Kill(const picojson::value& args) {
kill();
}
-void ApplicationManager::Launch(const picojson::value& args) {
+namespace {
+
+PlatformResult PrepareAppControlForLaunchAppControl(const picojson::value& args,
+ app_control_h* app_control) {
ScopeLogger();
- int callback_id = -1;
- const auto& callback = args.get(kCallbackId);
- if (callback.is<double>()) {
- callback_id = static_cast<int>(callback.get<double>());
+ const auto& control = args.get("appControl");
+ if (!control.is<picojson::object>()) {
+ return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
}
+ const picojson::object& app_control_obj = control.get<picojson::object>();
- std::shared_ptr<picojson::value> response(new picojson::value(picojson::object()));
- picojson::object& obj = response->get<picojson::object>();
- obj.insert(std::make_pair(kCallbackId, picojson::value(static_cast<double>(callback_id))));
+ app_control_h tmp_app_control = nullptr;
+ auto result = ApplicationUtils::ApplicationControlToService(app_control_obj, &tmp_app_control);
+ std::unique_ptr<std::remove_pointer<app_control_h>::type, decltype(&app_control_destroy)>
+ app_control_ptr(tmp_app_control, &app_control_destroy);
- const auto& app_id = args.get("id");
- if (!app_id.is<std::string>()) {
- PlatformResult ret =
- LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
- AsyncResponse(ret, &response);
- return;
+ if (result.IsError()) {
+ LoggerE("Application control to service failed.");
+ return result;
}
- const std::string& id = app_id.get<std::string>();
- auto launch = [id](const std::shared_ptr<picojson::value>& response) -> void {
- ScopeLogger("launch");
- PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
- const char* app_id = id.c_str();
- const int retry_count = 3;
+ std::string app_id;
+ const auto& id = args.get("id");
+ if (id.is<std::string>()) {
+ app_id = id.get<std::string>();
+ }
- int retry = 0;
- int ret = 0;
+ if (!app_id.empty()) {
+ LoggerD("app_id: %s", app_id.c_str());
- while (retry < retry_count) {
- ret = aul_open_app(app_id);
+ int ret = app_control_set_app_id(app_control_ptr.get(), app_id.c_str());
- if (ret >= 0) {
- break;
- }
-
- // delay 300ms for each retry
- struct timespec sleep_time = {0, 300L * 1000L * 1000L};
- nanosleep(&sleep_time, nullptr);
- ++retry;
-
- LoggerD("Retry launch request: %d", retry);
+ if (APP_CONTROL_ERROR_NONE != ret) {
+ LoggerE("Failed to set app id: %d (%s)", ret, get_error_message(ret));
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
}
+ }
- if (ret < 0) {
- result = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error has occurred.");
-
- LoggerD("Aul open return: %d (%s)", ret, get_error_message(ret));
- switch (ret) {
- case AUL_R_EINVAL:
- case AUL_R_ERROR:
- case AUL_R_ENOAPP:
- result =
- LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Launchpad returns not found error.",
- ("aul_open_app returns Not Found error"));
- break;
-
- case AUL_R_ECOMM:
- result = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Internal IPC error has occurred.",
- ("aul_open_app returns internal IPC error"));
- break;
- }
-
- LogAndReportError(result, &response->get<picojson::object>());
- } else {
- LoggerD("Launch request success");
- ReportSuccess(response->get<picojson::object>());
- }
- };
+ *app_control = app_control_ptr.release();
- launch(response);
- Instance::PostMessage(&this->instance_, response->serialize().c_str());
+ return PlatformResult(ErrorCode::NO_ERROR);
}
+} // namespace
+
void ApplicationManager::LaunchAppControl(const picojson::value& args) {
ScopeLogger();
@@ -465,180 +436,226 @@ void ApplicationManager::LaunchAppControl(const picojson::value& args) {
response_obj.insert(
std::make_pair(kCallbackId, picojson::value(static_cast<double>(callback_id))));
- PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
- const auto& control = args.get("appControl");
- if (!control.is<picojson::object>()) {
- result = LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
- AsyncResponse(result, &response);
- return;
- }
- const picojson::object& app_control_obj = control.get<picojson::object>();
-
- std::string launch_mode_str;
- const auto& launch_mode = control.get("launchMode");
- if (launch_mode.is<std::string>()) {
- launch_mode_str = launch_mode.get<std::string>();
- }
-
app_control_h app_control = nullptr;
- result = ApplicationUtils::ApplicationControlToService(app_control_obj, &app_control);
- std::shared_ptr<std::remove_pointer<app_control_h>::type> app_control_ptr(
- app_control, &app_control_destroy); // automatically release the memory
-
- if (result.IsError()) {
- LoggerE("Application control to service failed.");
- AsyncResponse(result, &response);
+ auto prepare_app_control_result = PrepareAppControlForLaunchAppControl(args, &app_control);
+ if (prepare_app_control_result.IsError()) {
+ AsyncResponse(LogAndCreateResult(prepare_app_control_result), &response);
return;
}
- std::string app_id;
- const auto& id = args.get("id");
- if (id.is<std::string>()) {
- app_id = id.get<std::string>();
- }
+ std::unique_ptr<std::remove_pointer<app_control_h>::type, decltype(&app_control_destroy)>
+ app_control_ptr(app_control, &app_control_destroy);
- std::string reply_callback;
+ std::string reply_callback_id;
const auto& reply = args.get("replyCallback");
if (reply.is<std::string>()) {
- reply_callback = reply.get<std::string>();
+ reply_callback_id = reply.get<std::string>();
}
- auto launch = [this, app_control_ptr, app_id, launch_mode_str,
- reply_callback](const std::shared_ptr<picojson::value>& response) -> void {
- ScopeLogger("Entered into asynchronous function, launch");
+ struct LaunchAppControlCallbackData {
+ ApplicationInstance* instance;
+ std::shared_ptr<picojson::value> response;
+ std::string reply_callback_id;
+ }* launch_app_user_data = new (std::nothrow)
+ LaunchAppControlCallbackData{&this->instance_, response, reply_callback_id};
- if (!app_id.empty()) {
- LoggerD("app_id: %s", app_id.c_str());
+ if (!launch_app_user_data) {
+ LoggerE("Memory allocation fail!");
+ AsyncResponse(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error."), &response);
+ return;
+ }
- int ret = app_control_set_app_id(app_control_ptr.get(), app_id.c_str());
+ app_control_reply_cb reply_callback = nullptr;
+ if (!reply_callback_id.empty()) {
+ launch_app_user_data->reply_callback_id = reply_callback_id;
- if (APP_CONTROL_ERROR_NONE != ret) {
- LogAndReportError(
- PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."),
- &response->get<picojson::object>(),
- ("Failed to set app id: %d (%s)", ret, get_error_message(ret)));
- return;
- }
- }
+ reply_callback = [](app_control_h request, app_control_h reply, app_control_result_e result,
+ void* user_data) {
+ ScopeLogger("reply_callback");
- if (!launch_mode_str.empty()) {
- app_control_launch_mode_e launch_mode;
-
- if ("SINGLE" == launch_mode_str) {
- launch_mode = APP_CONTROL_LAUNCH_MODE_SINGLE;
- } else if ("GROUP" == launch_mode_str) {
- launch_mode = APP_CONTROL_LAUNCH_MODE_GROUP;
- } else {
- ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."),
- &response->get<picojson::object>());
+ LaunchAppControlCallbackData* callback_data =
+ static_cast<LaunchAppControlCallbackData*>(user_data);
+ if (!callback_data) {
+ LoggerD("reply_callback failed: user_data is nullptr");
return;
}
- int ret = app_control_set_launch_mode(app_control_ptr.get(), launch_mode);
- if (APP_CONTROL_ERROR_NONE != ret) {
- LogAndReportError(PlatformResult(ErrorCode::NOT_FOUND_ERR, "Setting launch mode failed."),
- &response->get<picojson::object>(),
- ("Setting launch mode failed: %d (%s)", ret, get_error_message(ret)));
- return;
+ picojson::value return_value = picojson::value(picojson::object());
+ picojson::object& return_value_obj = return_value.get<picojson::object>();
+ return_value_obj.insert(
+ std::make_pair(kListenerId, picojson::value(callback_data->reply_callback_id)));
+
+ if (APP_CONTROL_RESULT_SUCCEEDED == result) {
+ LoggerD("App started");
+ return_value_obj.insert(std::make_pair("data", picojson::value(picojson::array())));
+ if (!ApplicationUtils::ServiceToApplicationControlDataArray(
+ reply, &return_value_obj.find("data")->second.get<picojson::array>())) {
+ return_value_obj.erase("data");
+ }
+ ReportSuccess(return_value_obj);
+ } else {
+ ReportError(return_value_obj);
}
- }
- app_control_reply_cb callback = nullptr;
- struct ReplayCallbackData {
- ApplicationInstance* app_instance;
- std::string reply_callback;
+ Instance::PostMessage(callback_data->instance, return_value.serialize().c_str());
+ delete callback_data;
};
+ }
- ReplayCallbackData* user_data = nullptr;
+ app_control_result_cb result_callback = [](app_control_h launch_request,
+ app_control_error_e launch_result, void* user_data) {
+ ScopeLogger("LaunchAppControl result_callback");
- if (!reply_callback.empty()) {
- user_data = new ReplayCallbackData();
- user_data->app_instance = &this->instance_;
- user_data->reply_callback = reply_callback;
+ LaunchAppControlCallbackData* callback_data =
+ static_cast<LaunchAppControlCallbackData*>(user_data);
- callback = [](app_control_h request, app_control_h reply, app_control_result_e result,
- void* user_data) {
- LoggerD("send_launch_request callback");
+ auto result = ApplicationUtils::TranslateAppControlError(launch_result);
- picojson::value return_value = picojson::value(picojson::object());
- picojson::object& return_value_obj = return_value.get<picojson::object>();
- ReplayCallbackData* reply_callback = static_cast<ReplayCallbackData*>(user_data);
+ if (result.IsError()) {
+ LogAndReportError(result, &(callback_data->response->get<picojson::object>()));
+ } else {
+ ReportSuccess(callback_data->response->get<picojson::object>());
+ }
- if (APP_CONTROL_RESULT_SUCCEEDED == result) {
- const std::string data = "data";
- return_value_obj.insert(std::make_pair(data, picojson::value(picojson::array())));
- if (!ApplicationUtils::ServiceToApplicationControlDataArray(
- reply, &return_value_obj.find(data)->second.get<picojson::array>())) {
- return_value_obj.erase(data);
- }
- ReportSuccess(return_value_obj);
- } else {
- ReportError(return_value_obj);
- }
+ Instance::PostMessage(callback_data->instance, callback_data->response->serialize().c_str());
- return_value_obj.insert(
- std::make_pair("listenerId", picojson::value(reply_callback->reply_callback)));
- Instance::PostMessage(reply_callback->app_instance, return_value.serialize().c_str());
- delete reply_callback;
- };
+ if (result.IsError() || (callback_data->reply_callback_id).empty()) {
+ delete callback_data;
}
+ };
- const int retry_count = 3;
+ /*
+ * TODO: Observe how often app_control_send_launch_request_async tries to launch the application.
+ * Previous implementation, using synchronous app_control_send_launch_request,
+ * tries to launch the application 3 times, before reporting an error.
+ * New implementation, using app_control_send_launch_request_async makes only one attempt.
+ * If problems, such as failed application start occur, multiple attempts may solve the problem.
+ */
+ auto launch_result =
+ ApplicationUtils::TranslateAppControlError(static_cast<app_control_error_e>(app_control_send_launch_request_async(
+ app_control_ptr.get(), result_callback, reply_callback, launch_app_user_data)));
+
+ if (launch_result.IsError()) {
+ delete launch_app_user_data;
+ AsyncResponse(launch_result, &response);
+ } else {
+ LoggerD("App launched");
+ }
+}
- int retry = 0;
- int ret = 0;
+namespace {
- while (retry < retry_count) {
- LoggerD("Calling launch request. Attempt number: %d", retry);
+PlatformResult TranslateLaunchError(app_control_error_e return_code) {
+ ScopeLogger();
- ret = app_control_send_launch_request(app_control_ptr.get(), callback, user_data);
- LoggerD("App control launch request returned: %d, %s", ret, get_error_message(ret));
- if (APP_CONTROL_ERROR_NONE == ret) {
- break;
- }
+ auto result = ApplicationUtils::TranslateAppControlError(return_code);
+ if (ErrorCode::SECURITY_ERR == result.error_code()) {
+ result = PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error.");
+ }
- // delay 300ms for each retry
- struct timespec sleep_time = {0, 300L * 1000L * 1000L};
- nanosleep(&sleep_time, nullptr);
- ++retry;
- }
+ return result;
+}
+
+PlatformResult PrepareAppControlForLaunch(const picojson::value& args, app_control_h* app_control) {
+ ScopeLogger();
+
+ const auto& app_id = args.get("id");
+ if (!app_id.is<std::string>()) {
+ return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
+ }
+ const auto app_id_str = app_id.get<std::string>();
+
+ app_control_h tmp_app_control = nullptr;
+ int result = app_control_create(&tmp_app_control);
+ if (APP_CONTROL_ERROR_NONE != result) {
+ LoggerD("app_control_create() failed: %d (%s)", result, get_error_message(result));
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.");
+ }
+
+ std::unique_ptr<std::remove_pointer<app_control_h>::type, decltype(&app_control_destroy)>
+ app_control_ptr(tmp_app_control, &app_control_destroy);
+
+ if (!app_id_str.empty()) {
+ LoggerD("app_id: %s", app_id_str.c_str());
+
+ int ret = app_control_set_app_id(app_control_ptr.get(), app_id_str.c_str());
if (APP_CONTROL_ERROR_NONE != ret) {
- delete user_data;
-
- switch (ret) {
- case APP_CONTROL_ERROR_INVALID_PARAMETER:
- LogAndReportError(
- PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter returned."),
- &response->get<picojson::object>(),
- ("app_control_send_launch_request returns APP_CONTROL_ERROR_INVALID_PARAMETER"));
- return;
- case APP_CONTROL_ERROR_OUT_OF_MEMORY:
- LogAndReportError(
- PlatformResult(ErrorCode::UNKNOWN_ERR, "Out of memory."),
- &response->get<picojson::object>(),
- ("app_control_send_launch_request returns APP_CONTROL_ERROR_OUT_OF_MEMORY"));
- return;
- case APP_CONTROL_ERROR_LAUNCH_REJECTED:
- case APP_CONTROL_ERROR_APP_NOT_FOUND:
- LogAndReportError(
- PlatformResult(ErrorCode::NOT_FOUND_ERR, "No matched application found."),
- &response->get<picojson::object>(),
- ("app_control_send_launch_request returns APP_CONTROL_ERROR_APP_NOT_FOUND"));
- return;
- default:
- LogAndReportError(
- PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error."),
- &response->get<picojson::object>(),
- ("app_control_send_launch_request returns: %d (%s)", ret, get_error_message(ret)));
- return;
- }
+ LoggerE("Failed to set app id: %d (%s)", ret, get_error_message(ret));
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
}
- ReportSuccess(response->get<picojson::object>());
+ }
+
+ *app_control = app_control_ptr.release();
+
+ return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+} // namespace
+void ApplicationManager::Launch(const picojson::value& args) {
+ ScopeLogger();
+
+ int callback_id = -1;
+ const auto& callback = args.get(kCallbackId);
+ if (callback.is<double>()) {
+ callback_id = static_cast<int>(callback.get<double>());
+ }
+
+ std::shared_ptr<picojson::value> response(new picojson::value(picojson::object()));
+ picojson::object& response_obj = response->get<picojson::object>();
+ response_obj.insert(
+ std::make_pair(kCallbackId, picojson::value(static_cast<double>(callback_id))));
+
+ app_control_h app_control = nullptr;
+ auto prepare_app_control_result = PrepareAppControlForLaunch(args, &app_control);
+ if (prepare_app_control_result.IsError()) {
+ AsyncResponse(LogAndCreateResult(prepare_app_control_result), &response);
+ return;
+ }
+
+ std::unique_ptr<std::remove_pointer<app_control_h>::type, decltype(&app_control_destroy)>
+ app_control_ptr(app_control, &app_control_destroy);
+
+ struct LaunchCallbackData {
+ ApplicationInstance* instance;
+ std::shared_ptr<picojson::value> response;
+ }* launch_user_data = new (std::nothrow) LaunchCallbackData{&this->instance_, response};
+
+ app_control_result_cb result_callback = [](app_control_h launch_request,
+ app_control_error_e launch_result, void* user_data) {
+ ScopeLogger("Launch result_callback");
+
+ LaunchCallbackData* callback_data = static_cast<LaunchCallbackData*>(user_data);
+
+ auto result = TranslateLaunchError(launch_result);
+
+ if (result.IsError()) {
+ LogAndReportError(result, &(callback_data->response->get<picojson::object>()));
+ } else {
+ ReportSuccess(callback_data->response->get<picojson::object>());
+ }
+
+ Instance::PostMessage(callback_data->instance, callback_data->response->serialize().c_str());
+
+ delete callback_data;
};
- launch(response);
- Instance::PostMessage(&this->instance_, response->serialize().c_str());
+ /*
+ * TODO: Observe how often app_control_send_launch_request_async tries to launch the application.
+ * Previous implementation, using synchronous app_control_send_launch_request,
+ * tries to launch the application 3 times, before reporting an error.
+ * New implementation, using app_control_send_launch_request_async makes only one attempt.
+ * If problems, such as failed application start occur, multiple attempts may solve the problem.
+ */
+ auto launch_result = TranslateLaunchError(static_cast<app_control_error_e>(app_control_send_launch_request_async(
+ app_control_ptr.get(), result_callback, nullptr, launch_user_data)));
+
+ if (launch_result.IsError()) {
+ delete launch_user_data;
+ AsyncResponse(launch_result, &response);
+ } else {
+ LoggerD("App launched");
+ }
}
// internal impl of app_control_foreach_app_matched() for handling APP_CONTROL_ERROR_APP_NOT_FOUND
@@ -1368,8 +1385,6 @@ void ApplicationManager::GetBatteryUsageInfo(const picojson::value& args, picojs
TaskQueue::GetInstance().Queue<picojson::value>(get_battery_usage, get_battery_usage_response,
data);
#else
- // 20170510 Context API is supported only for mobile profile, other ones would result with
- // NotSupportedError
LogAndReportError(PlatformResult(ErrorCode::NOT_SUPPORTED_ERR,
"This feature is not supported on this profile."),
out, ("NOT_SUPPORTED_ERR: This feature is not supported on this profile"));
@@ -1404,8 +1419,6 @@ void ApplicationManager::GetAppsUsageInfo(const picojson::value& args, picojson:
TaskQueue::GetInstance().Queue<picojson::value>(get_apps_usage, get_apps_usage_response, data);
#else
- // Context API is supported only for mobile profile, other ones would result with
- // NotSupportedError
LogAndReportError(PlatformResult(ErrorCode::NOT_SUPPORTED_ERR,
"This feature is not supported on this profile."),
out, ("NOT_SUPPORTED_ERR: This feature is not supported on this profile"));
diff --git a/src/application/application_manager.h b/src/application/application_manager.h
index c1fa8ad2..be0ebbf6 100644
--- a/src/application/application_manager.h
+++ b/src/application/application_manager.h
@@ -64,7 +64,8 @@ class ApplicationManager {
void StartAppInfoEventListener(picojson::object* out);
void StopAppInfoEventListener();
void GetApplicationInformationSize(const picojson::value& args, picojson::object* out);
- void AsyncResponse(common::PlatformResult& result, std::shared_ptr<picojson::value>* response);
+ void AsyncResponse(const common::PlatformResult& result,
+ std::shared_ptr<picojson::value>* response);
void BroadcastEventHelper(const picojson::value& args, picojson::object& out, bool trusted);
common::PlatformResult StartEventListener(const std::string& event_name,
diff --git a/src/application/application_utils.cc b/src/application/application_utils.cc
index 596d292a..3fbeeba5 100644
--- a/src/application/application_utils.cc
+++ b/src/application/application_utils.cc
@@ -183,64 +183,182 @@ void ApplicationUtils::CreateApplicationMetaData(const char* key, const char* va
app_meta_data->insert(std::make_pair("value", picojson::value(value)));
}
+namespace {
+
+const std::string kOperationAppControlField = "operation";
+const std::string kURIAppControlField = "uri";
+const std::string kMIMEAppControlField = "mime";
+const std::string kCategoryAppControlField = "category";
+const std::string kLaunchModeAppControlField = "launchMode";
+const std::string kDataAppControlField = "data";
+
+const std::string kGroupLaunchMode = "GROUP";
+const std::string kSingleLaunchMode = "SINGLE";
+
+using AppControlTextFieldSetter = std::function<int(app_control_h, const char*)>;
+// clang-format off
+const std::map<std::string, AppControlTextFieldSetter> AppControlTextFieldSetters = {
+ { kOperationAppControlField, app_control_set_operation },
+ { kURIAppControlField, app_control_set_uri },
+ { kMIMEAppControlField, app_control_set_mime },
+ { kCategoryAppControlField, app_control_set_category }
+}; // clang-format on
+
+PlatformResult SetAppControlTextField(app_control_h app_control, const std::string& field_name,
+ const std::string& value) {
+ ScopeLogger("Field: %s, value: %s", field_name.c_str(), value.c_str());
+
+ auto setter_it = AppControlTextFieldSetters.find(field_name);
+ if (AppControlTextFieldSetters.end() == setter_it) {
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.");
+ }
+ auto setter = setter_it->second;
+
+ auto result = setter(app_control, value.c_str());
+ auto result_translated =
+ ApplicationUtils::TranslateAppControlError(static_cast<app_control_error_e>(result));
+
+ if (result_translated.IsError()) {
+ LoggerD("Setting app_control's %s field failed: %s", field_name.c_str(),
+ result_translated.message().c_str());
+ }
+
+ return result_translated;
+}
+
+app_control_launch_mode_e LaunchModeStringToEnum(const std::string& launch_mode) {
+ ScopeLogger();
+
+ return launch_mode == kGroupLaunchMode ? APP_CONTROL_LAUNCH_MODE_GROUP
+ : APP_CONTROL_LAUNCH_MODE_SINGLE;
+}
+
+bool LaunchModeIsInvalid(const std::string& launch_mode) {
+ ScopeLogger();
+
+ auto is_valid = launch_mode == kSingleLaunchMode || launch_mode == kGroupLaunchMode;
+ LoggerD("Launch mode: %s (%s)", launch_mode.c_str(), is_valid ? "valid" : "invalid");
+
+ return !is_valid;
+}
+
+PlatformResult SetAppControlLaunchModeField(app_control_h app_control,
+ const std::string& launch_mode_str) {
+ ScopeLogger();
+
+ if (LaunchModeIsInvalid(launch_mode_str)) {
+ LoggerD("Invalid launchMode value: %s", launch_mode_str.c_str());
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR,
+ "Invalid launchMode value: " + launch_mode_str);
+ }
+
+ auto result = app_control_set_launch_mode(app_control, LaunchModeStringToEnum(launch_mode_str));
+ return ApplicationUtils::TranslateAppControlError(static_cast<app_control_error_e>(result));
+}
+
+PlatformResult SetAppControlDataField(app_control_h app_control, const picojson::array& data) {
+ ScopeLogger();
+
+ for (auto iter = data.begin(); iter != data.end(); ++iter) {
+ if (iter->is<picojson::object>()) {
+ PlatformResult ret = ApplicationUtils::ApplicationControlDataToServiceExtraData(
+ iter->get<picojson::object>(), app_control);
+ if (ret.IsError()) {
+ return ret;
+ }
+ } else {
+ LoggerD("Invalid data value: not an object");
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid data type: not an object");
+ }
+ }
+
+ return PlatformResult{ErrorCode::NO_ERROR};
+}
+
+PlatformResult SetAppControlFieldIfValueSpecified(
+ app_control_h app_control, const std::string& field_name,
+ const picojson::object::const_iterator& iterator) {
+ ScopeLogger();
+
+ if (iterator->second.is<std::string>()) {
+ if (field_name != kLaunchModeAppControlField) {
+ return SetAppControlTextField(app_control, field_name, iterator->second.get<std::string>());
+ }
+ return SetAppControlLaunchModeField(app_control, iterator->second.get<std::string>());
+ } else if (iterator->second.is<picojson::array>() && kDataAppControlField == field_name) {
+ return SetAppControlDataField(app_control, iterator->second.get<picojson::array>());
+ }
+
+ return PlatformResult{ErrorCode::NO_ERROR};
+}
+
+} // namespace
+
PlatformResult ApplicationUtils::ApplicationControlToService(
const picojson::object& app_control_obj, app_control_h* app_control) {
ScopeLogger();
- const auto it_operation = app_control_obj.find("operation");
- const auto it_uri = app_control_obj.find("uri");
- const auto it_mime = app_control_obj.find("mime");
- const auto it_category = app_control_obj.find("category");
- const auto it_data = app_control_obj.find("data");
+
+ const auto it_operation = app_control_obj.find(kOperationAppControlField);
+ const auto it_uri = app_control_obj.find(kURIAppControlField);
+ const auto it_mime = app_control_obj.find(kMIMEAppControlField);
+ const auto it_category = app_control_obj.find(kCategoryAppControlField);
+ const auto it_data = app_control_obj.find(kDataAppControlField);
+ const auto it_launch_mode = app_control_obj.find(kLaunchModeAppControlField);
const auto it_app_control_end = app_control_obj.end();
if (it_operation == it_app_control_end || it_uri == it_app_control_end ||
it_mime == it_app_control_end || it_category == it_app_control_end ||
it_data == it_app_control_end || !it_operation->second.is<std::string>() ||
- !it_data->second.is<picojson::array>()) {
+ !it_data->second.is<picojson::array>() || it_launch_mode == it_app_control_end) {
return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter was passed.");
}
app_control_h app_control_tmp = nullptr;
int result = app_control_create(&app_control_tmp);
-
if (APP_CONTROL_ERROR_NONE != result) {
- return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Creation AppControl failed.",
- ("Problem with create handle."));
+ LoggerD("app_control_create() failed: %d (%s)", result, get_error_message(result));
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.");
}
std::unique_ptr<std::remove_pointer<app_control_h>::type, int (*)(app_control_h)> app_control_ptr(
app_control_tmp, &app_control_destroy);
- // operation
- app_control_set_operation(app_control_tmp, it_operation->second.get<std::string>().c_str());
+ auto set_field_result = PlatformResult(ErrorCode::UNKNOWN_ERR);
+
+ set_field_result =
+ SetAppControlFieldIfValueSpecified(app_control_tmp, kOperationAppControlField, it_operation);
+ if (set_field_result.IsError()) {
+ return set_field_result;
+ }
- // uri
- if (it_uri->second.is<std::string>()) {
- app_control_set_uri(app_control_tmp, it_uri->second.get<std::string>().c_str());
+ set_field_result =
+ SetAppControlFieldIfValueSpecified(app_control_tmp, kURIAppControlField, it_uri);
+ if (set_field_result.IsError()) {
+ return set_field_result;
}
- // mime
- if (it_mime->second.is<std::string>()) {
- app_control_set_mime(app_control_tmp, it_mime->second.get<std::string>().c_str());
+ set_field_result =
+ SetAppControlFieldIfValueSpecified(app_control_tmp, kMIMEAppControlField, it_mime);
+ if (set_field_result.IsError()) {
+ return set_field_result;
}
- // category
- if (it_category->second.is<std::string>()) {
- app_control_set_category(app_control_tmp, it_category->second.get<std::string>().c_str());
+ set_field_result =
+ SetAppControlFieldIfValueSpecified(app_control_tmp, kCategoryAppControlField, it_category);
+ if (set_field_result.IsError()) {
+ return set_field_result;
}
- // ApplicationControlData
- const picojson::array& data = it_data->second.get<picojson::array>();
+ set_field_result = SetAppControlFieldIfValueSpecified(app_control_tmp, kLaunchModeAppControlField,
+ it_launch_mode);
+ if (set_field_result.IsError()) {
+ return set_field_result;
+ }
- for (auto iter = data.begin(); iter != data.end(); ++iter) {
- if (iter->is<picojson::object>()) {
- PlatformResult ret =
- ApplicationControlDataToServiceExtraData(iter->get<picojson::object>(), app_control_tmp);
- if (ret.IsError()) {
- LoggerE("Failed ApplicationControlDataToServiceExtraData()");
- return ret;
- }
- }
+ set_field_result =
+ SetAppControlFieldIfValueSpecified(app_control_tmp, kDataAppControlField, it_data);
+ if (set_field_result.IsError()) {
+ return set_field_result;
}
*app_control = app_control_ptr.release();
@@ -259,27 +377,43 @@ PlatformResult ApplicationUtils::ApplicationControlDataToServiceExtraData(
if (it_key == it_app_control_data_end || it_value == it_app_control_data_end ||
!it_key->second.is<std::string>() || !it_value->second.is<picojson::array>()) {
return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter was passed.",
- ("Problem with key or value."));
+ ("Invalid key or value."));
}
const std::string& key = it_key->second.get<std::string>();
const picojson::array& value = it_value->second.get<picojson::array>();
- const size_t size = value.size();
- const char** arr = new const char*[size];
- size_t i = 0;
+ std::vector<const char*> value_data;
- for (auto iter = value.begin(); iter != value.end(); ++iter, ++i) {
- arr[i] = iter->get<std::string>().c_str();
+ for (auto& v : value) {
+ value_data.push_back(v.get<std::string>().c_str());
}
- if (1 == size) {
- app_control_add_extra_data(app_control, key.c_str(), arr[0]);
+ int result = APP_CONTROL_ERROR_NONE;
+ /*
+ * Native applications handle single extra data objects and arrays in a different ways,
+ * hence they have to be packed with different native API functions.
+ */
+ if (1 == value_data.size()) {
+ result = app_control_add_extra_data(app_control, key.c_str(), value_data[0]);
} else {
- app_control_add_extra_data_array(app_control, key.c_str(), arr, size);
+ result = app_control_add_extra_data_array(app_control, key.c_str(), value_data.data(), value_data.size());
+ }
+
+ if (APP_CONTROL_ERROR_INVALID_PARAMETER == result) {
+ if (0 == key.length()) {
+ LoggerD("app_control_add_extra_data_array failed: zero-length key");
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR,
+ "Invalid AppControlData key: key length is 0.");
+ }
+ LoggerD("app_control_add_extra_data_array failed: invalid parameter passed");
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR,
+ "Invalid AppControlData value, associated with key: " + key);
+ } else if (APP_CONTROL_ERROR_KEY_REJECTED == result) {
+ LoggerD("app_control_add_extra_data_array failed: key rejected");
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid AppControlData's key: " + key);
}
- delete[] arr;
return PlatformResult(ErrorCode::NO_ERROR);
}
@@ -295,42 +429,68 @@ void ApplicationUtils::ServiceToApplicationControl(app_control_h app_control,
};
ret = app_control_get_operation(app_control, &tmp_str);
- if ((APP_CONTROL_ERROR_NONE == ret) && (nullptr != tmp_str)) {
+ if (APP_CONTROL_ERROR_NONE != ret) {
+ LoggerE("Get operation failed: %d (%s)", ret, get_error_message(ret));
+ } else if (tmp_str) {
LoggerD("operation: %s", tmp_str);
- app_control_obj->insert(std::make_pair("operation", picojson::value(std::string(tmp_str))));
+ app_control_obj->insert(
+ std::make_pair(kOperationAppControlField, picojson::value(std::string(tmp_str))));
} else {
- LoggerE("Get operation failed: %d (%s)", ret, get_error_message(ret));
+ LoggerD("operation field is empty");
}
clear(tmp_str);
ret = app_control_get_uri(app_control, &tmp_str);
- if ((APP_CONTROL_ERROR_NONE == ret) && (nullptr != tmp_str)) {
+ if (APP_CONTROL_ERROR_NONE != ret) {
+ LoggerE("Get URI failed: %d (%s)", ret, get_error_message(ret));
+ } else if (tmp_str) {
LoggerD("URI: %s", tmp_str);
- app_control_obj->insert(std::make_pair("uri", picojson::value(std::string(tmp_str))));
+ app_control_obj->insert(
+ std::make_pair(kURIAppControlField, picojson::value(std::string(tmp_str))));
+ } else {
+ LoggerD("URI field is empty");
}
clear(tmp_str);
ret = app_control_get_mime(app_control, &tmp_str);
- if ((APP_CONTROL_ERROR_NONE == ret) && (nullptr != tmp_str)) {
+ if (APP_CONTROL_ERROR_NONE != ret) {
+ LoggerE("Get MIME failed: %d (%s)", ret, get_error_message(ret));
+ } else if (tmp_str) {
LoggerD("MIME: %s", tmp_str);
- app_control_obj->insert(std::make_pair("mime", picojson::value(std::string(tmp_str))));
+ app_control_obj->insert(
+ std::make_pair(kMIMEAppControlField, picojson::value(std::string(tmp_str))));
} else {
- LoggerE("Get mime failed: %d (%s)", ret, get_error_message(ret));
+ LoggerD("MIME field is empty");
}
clear(tmp_str);
ret = app_control_get_category(app_control, &tmp_str);
- if ((APP_CONTROL_ERROR_NONE == ret) && (nullptr != tmp_str)) {
+ if (APP_CONTROL_ERROR_NONE != ret) {
+ LoggerE("Get category failed: %d (%s)", ret, get_error_message(ret));
+ } else if (tmp_str) {
LoggerD("category: %s", tmp_str);
- app_control_obj->insert(std::make_pair("category", picojson::value(std::string(tmp_str))));
+ app_control_obj->insert(
+ std::make_pair(kCategoryAppControlField, picojson::value(std::string(tmp_str))));
} else {
- LoggerE("Get category failed: %d (%s)", ret, get_error_message(ret));
+ LoggerD("category field is empty");
}
clear(tmp_str);
- app_control_obj->insert(std::make_pair("data", picojson::value(picojson::array())));
+ app_control_launch_mode_e launch_mode = APP_CONTROL_LAUNCH_MODE_SINGLE;
+ ret = app_control_get_launch_mode(app_control, &launch_mode);
+ if (APP_CONTROL_ERROR_NONE != ret) {
+ LoggerE("Get launch mode failed: %d (%s)", ret, get_error_message(ret));
+ } else {
+ std::string launch_mode_str =
+ launch_mode == APP_CONTROL_LAUNCH_MODE_SINGLE ? kSingleLaunchMode : kGroupLaunchMode;
+ LoggerD("launch mode: %s", launch_mode_str.c_str());
+ app_control_obj->insert(
+ std::make_pair(kLaunchModeAppControlField, picojson::value(launch_mode_str)));
+ }
+
+ app_control_obj->insert(std::make_pair(kDataAppControlField, picojson::value(picojson::array())));
ServiceToApplicationControlDataArray(
- app_control, &app_control_obj->find("data")->second.get<picojson::array>());
+ app_control, &app_control_obj->find(kDataAppControlField)->second.get<picojson::array>());
}
void ApplicationUtils::ServiceExtraDataToApplicationControlData(
@@ -391,6 +551,36 @@ bool ApplicationUtils::ServiceToApplicationControlDataArray(app_control_h app_co
return APP_CONTROL_ERROR_NONE == ret;
}
+PlatformResult ApplicationUtils::TranslateAppControlError(app_control_error_e return_code) {
+ ScopeLogger("Return code: %d (%s)", static_cast<int>(return_code),
+ get_error_message(static_cast<int>(return_code)));
+
+ switch (return_code) {
+ case APP_CONTROL_ERROR_NONE:
+ return PlatformResult(ErrorCode::NO_ERROR);
+
+ case APP_CONTROL_ERROR_INVALID_PARAMETER:
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
+
+ case APP_CONTROL_ERROR_APP_NOT_FOUND:
+ return PlatformResult(ErrorCode::NOT_FOUND_ERR, "No matched application found.");
+
+ case APP_CONTROL_ERROR_PERMISSION_DENIED:
+ return PlatformResult(ErrorCode::SECURITY_ERR, "Permission denied.");
+
+ case APP_CONTROL_ERROR_OUT_OF_MEMORY:
+ case APP_CONTROL_ERROR_KEY_NOT_FOUND:
+ case APP_CONTROL_ERROR_KEY_REJECTED:
+ case APP_CONTROL_ERROR_INVALID_DATA_TYPE:
+ case APP_CONTROL_ERROR_LAUNCH_REJECTED:
+ case APP_CONTROL_ERROR_LAUNCH_FAILED:
+ case APP_CONTROL_ERROR_TIMED_OUT:
+ case APP_CONTROL_ERROR_IO_ERROR:
+ default:
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error.");
+ }
+}
+
bool ApplicationUtils::ServiceExtraDataCallback(app_control_h app_control, const char* key,
void* user_data) {
ScopeLogger();
diff --git a/src/application/application_utils.h b/src/application/application_utils.h
index 455f1977..308827be 100644
--- a/src/application/application_utils.h
+++ b/src/application/application_utils.h
@@ -59,6 +59,8 @@ class ApplicationUtils {
static bool ServiceToApplicationControlDataArray(app_control_h app_control,
picojson::array* data);
+ static common::PlatformResult TranslateAppControlError(app_control_error_e error_code);
+
private:
static bool ServiceExtraDataCallback(app_control_h app_control, const char* key, void* user_data);
};
diff --git a/src/archive/archive_api.js b/src/archive/archive_api.js
index 750eceff..61c2b993 100755
--- a/src/archive/archive_api.js
+++ b/src/archive/archive_api.js
@@ -22,23 +22,46 @@ var privUtils_ = xwalk.utils;
function CommonFS() {}
CommonFS.cacheVirtualToReal = {};
+CommonFS.isCacheReady = false;
+CommonFS.listenerRegistered = false;
+
+function clearCache() {
+ CommonFS.cacheVirtualToReal = {};
+ CommonFS.isCacheReady = false;
+}
function _initializeCache() {
- try {
- var result = native_.callSync('Archive_fetchVirtualRoots', {});
+ if (CommonFS.isCacheReady) {
+ return;
+ }
+ var result = native_.callSync('Archive_fetchStorages', {});
- if (native_.isFailure(result)) {
- throw native_.getErrorObject(result);
- }
+ if (native_.isFailure(result)) {
+ privUtils_.log(
+ 'Exception while getting widget paths was thrown: ' +
+ native_.getErrorObject(result).message
+ );
+ return;
+ }
- result = native_.getResultObject(result);
- for (var i = 0; i < result.length; ++i) {
- CommonFS.cacheVirtualToReal[result[i].name] = {
- path: result[i].path
- };
+ result = native_.getResultObject(result);
+ for (var i = 0; i < result.length; ++i) {
+ CommonFS.cacheVirtualToReal[result[i].name] = {
+ path: result[i].path
+ };
+ }
+ CommonFS.isCacheReady = true;
+ if (!CommonFS.listenerRegistered) {
+ try {
+ tizen.filesystem.addStorageStateChangeListener(clearCache);
+ CommonFS.listenerRegistered = true;
+ } catch (e) {
+ privUtils_.log(
+ 'Failed to register storage change listener, ' +
+ 'storage information may be corrupted: ' +
+ e.message
+ );
}
- } catch (e) {
- privUtils_.log('Exception while getting widget paths was thrown: ' + e);
}
}
@@ -52,6 +75,7 @@ CommonFS.toRealPath = function(aPath) {
_fileRealPath = aPath.substr(_uriPrefix.length);
} else if (aPath[0] != '/') {
// virtual path$
+ _initializeCache();
var _pathTokens = aPath.split('/');
if (
this.cacheVirtualToReal[_pathTokens[0]] &&
@@ -77,7 +101,7 @@ CommonFS.toRealPath = function(aPath) {
CommonFS.isVirtualPath = function(aPath) {
var root = aPath.split('/')[0];
-
+ _initializeCache();
return this.cacheVirtualToReal[root] != undefined;
};
@@ -178,8 +202,8 @@ var ArchiveFileProgressCallback = function(msg) {
native_.addListener(ARCHIVE_ONPROGRESS_CALLBACK, ArchiveFileProgressCallback);
/**
- * The ArchiveFileEntry interface provides access to ArchiveFile member information and
- * file data.
+ * The ArchiveFileEntry interface provides access to ArchiveFile member information
+ * and file data.
* This constructor is for internal use only.
* It should be prohibited to call this constructor by user.
*/
@@ -216,10 +240,7 @@ function ArchiveFileEntry(data, priv) {
*/
this.extract = function() {
var args = validator_.validateArgs(arguments, [
- {
- name: 'destinationDirectory',
- type: types_.FILE_REFERENCE
- },
+ { name: 'destinationDirectory', type: types_.FILE_REFERENCE },
{
name: 'onsuccess',
type: types_.FUNCTION,
@@ -330,10 +351,7 @@ function ArchiveFile(data) {
*/
this.add = function() {
var args = validator_.validateArgs(arguments, [
- {
- name: 'sourceFile',
- type: types_.FILE_REFERENCE
- },
+ { name: 'sourceFile', type: types_.FILE_REFERENCE },
{
name: 'onsuccess',
type: types_.FUNCTION,
@@ -416,10 +434,7 @@ function ArchiveFile(data) {
*/
this.extractAll = function() {
var args = validator_.validateArgs(arguments, [
- {
- name: 'destinationDirectory',
- type: types_.FILE_REFERENCE
- },
+ { name: 'destinationDirectory', type: types_.FILE_REFERENCE },
{
name: 'onsuccess',
type: types_.FUNCTION,
@@ -523,8 +538,8 @@ function ArchiveFile(data) {
};
/**
- * Retrieves information about ArchiveFileEntry with the specified name
- * in ArchiveFile.
+ * Retrieves information about ArchiveFileEntry with the specified name in
+ * ArchiveFile.
*/
this.getEntryByName = function() {
var args = validator_.validateArgs(arguments, [
@@ -579,8 +594,8 @@ function ArchiveFile(data) {
var ArchiveManager = function() {};
/**
- * Opens the archive file.
- * After this operation, it is possible to add or get files to and from the archive.
+ * Opens the archive file. After this operation, it is possible to add or get files
+ * to and from the archive.
*/
ArchiveManager.prototype.open = function() {
var args = validator_.validateArgs(arguments, [
diff --git a/src/archive/archive_file.cc b/src/archive/archive_file.cc
index 0f911990..94ec9dbf 100644
--- a/src/archive/archive_file.cc
+++ b/src/archive/archive_file.cc
@@ -76,7 +76,7 @@ ArchiveFile::~ArchiveFile() {
ScopeLogger();
if (m_entry_map) {
- LoggerD("Unlinking old m_entry_map: %d ArchiveFileEntries", m_entry_map->size());
+ LoggerD("Unlinking old m_entry_map: %zu ArchiveFileEntries", m_entry_map->size());
for (auto it = m_entry_map->begin(); it != m_entry_map->end(); ++it) {
if (it->second) {
it->second->setArchiveFileNonProtectPtr(NULL);
@@ -537,7 +537,7 @@ void ArchiveFile::setEntryMap(ArchiveFileEntryPtrMapPtr entries) {
ScopeLogger();
if (m_entry_map) {
- LoggerD("Unlinking old m_entry_map: %d ArchiveFileEntries", m_entry_map->size());
+ LoggerD("Unlinking old m_entry_map: %zu ArchiveFileEntries", m_entry_map->size());
for (auto it = m_entry_map->begin(); it != m_entry_map->end(); ++it) {
if (it->second) {
it->second->setArchiveFileNonProtectPtr(NULL);
@@ -547,7 +547,7 @@ void ArchiveFile::setEntryMap(ArchiveFileEntryPtrMapPtr entries) {
m_entry_map = entries;
- LoggerD("Linking new m_entry_map ArchiveFileEntries (%d) with ArchiveFile object",
+ LoggerD("Linking new m_entry_map ArchiveFileEntries (%zu) with ArchiveFile object",
m_entry_map->size());
for (auto it = m_entry_map->begin(); it != m_entry_map->end(); ++it) {
if (it->second) {
diff --git a/src/archive/archive_instance.cc b/src/archive/archive_instance.cc
index ae2745cb..cf7f9c8c 100644
--- a/src/archive/archive_instance.cc
+++ b/src/archive/archive_instance.cc
@@ -72,7 +72,7 @@ ArchiveInstance::ArchiveInstance() {
REGISTER_ASYNC("ArchiveFileEntry_extract", Extract);
- REGISTER_SYNC("Archive_fetchVirtualRoots", FetchVirtualRoots);
+ REGISTER_SYNC("Archive_fetchStorages", FetchStorages);
#undef REGISTER_ASYNC
#undef REGISTER_SYNC
@@ -101,9 +101,10 @@ void ArchiveInstance::Open(const picojson::value& args, picojson::object& out) {
ScopeLogger("%s", args.serialize().c_str());
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
-
picojson::object data = args.get<picojson::object>();
picojson::value v_file = data.at(PARAM_FILE);
+ CHECK_STORAGE_ACCESS(v_file.get<std::string>(), &out);
+
picojson::value v_mode = data.at(PARAM_MODE);
picojson::value v_op_id = data.at(PARAM_OPERATION_ID);
picojson::object options = data.at(PARAM_OPTIONS).get<picojson::object>();
@@ -146,7 +147,7 @@ void ArchiveInstance::Open(const picojson::value& args, picojson::object& out) {
}
file_ptr = FilePtr(new File(node, File::PermissionList()));
- LoggerD("open: %s mode: 0x%x overwrite: %d", location_full_path.c_str(), fm, overwrite);
+ LoggerD("open: %s mode: 0x%d overwrite: %d", location_full_path.c_str(), fm, overwrite);
if (FileMode::WRITE == fm || FileMode::READ_WRITE == fm) {
if (overwrite) {
LoggerD("Deleting existing file: %s", location_full_path.c_str());
@@ -260,9 +261,10 @@ void ArchiveInstance::Add(const picojson::value& args, picojson::object& out) {
ScopeLogger("%s", args.serialize().c_str());
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
-
picojson::object data = args.get<picojson::object>();
picojson::value v_source = data.at(PARAM_SOURCE_FILE);
+ CHECK_STORAGE_ACCESS(v_source.get<std::string>(), &out);
+
picojson::value v_options = data.at(PARAM_OPTIONS);
picojson::value v_op_id = data.at(PARAM_OPERATION_ID);
picojson::value v_handle = data.at(ARCHIVE_FILE_HANDLE);
@@ -347,9 +349,10 @@ void ArchiveInstance::ExtractAll(const picojson::value& args, picojson::object&
ScopeLogger("%s", args.serialize().c_str());
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
-
picojson::object data = args.get<picojson::object>();
picojson::value v_dest_dir = data.at(PARAM_DESTINATION_DIR);
+ CHECK_STORAGE_ACCESS(v_dest_dir.get<std::string>(), &out);
+
picojson::value v_overwrite = data.at(PARAM_OVERWRITE);
picojson::value v_op_id = data.at(PARAM_OPERATION_ID);
picojson::value v_handle = data.at(ARCHIVE_FILE_HANDLE);
@@ -520,9 +523,10 @@ void ArchiveInstance::Extract(const picojson::value& args, picojson::object& out
ScopeLogger("%s", args.serialize().c_str());
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
-
picojson::object data = args.get<picojson::object>();
picojson::value v_dest_dir = data.at(PARAM_DESTINATION_DIR);
+ CHECK_STORAGE_ACCESS(v_dest_dir.get<std::string>(), &out);
+
picojson::value v_strip_name = data.at(PARAM_STRIP_NAME);
picojson::value v_overwrite = data.at(PARAM_OVERWRITE);
picojson::value v_op_id = data.at(PARAM_OPERATION_ID);
@@ -596,14 +600,14 @@ void ArchiveInstance::Extract(const picojson::value& args, picojson::object& out
}
}
-void ArchiveInstance::FetchVirtualRoots(const picojson::value& args, picojson::object& out) {
+void ArchiveInstance::FetchStorages(const picojson::value& args, picojson::object& out) {
ScopeLogger();
- picojson::array roots;
- for (const auto& root : common::FilesystemProvider::Create().GetVirtualPaths()) {
- roots.push_back(root.ToJson());
+ picojson::array storages;
+ for (const auto& storage : common::FilesystemProvider::Create().GetAllStorages()) {
+ storages.push_back(storage->ToJson());
}
- ReportSuccess(picojson::value(roots), out);
+ ReportSuccess(picojson::value(storages), out);
}
} // namespace archive
diff --git a/src/archive/archive_instance.h b/src/archive/archive_instance.h
index 8b55ebf2..c9e418b3 100644
--- a/src/archive/archive_instance.h
+++ b/src/archive/archive_instance.h
@@ -48,7 +48,7 @@ class ArchiveInstance : public common::ParsedInstance {
void Extract(const picojson::value& args, picojson::object& out);
/* Filesystem related method */
- void FetchVirtualRoots(const picojson::value& args, picojson::object& out);
+ void FetchStorages(const picojson::value& args, picojson::object& out);
void PostError(const common::PlatformException& e, double callback_id);
void PostError(const common::PlatformResult& e, double callback_id);
diff --git a/src/archive/filesystem_node.cc b/src/archive/filesystem_node.cc
index 13d23f7e..1d8048c2 100644
--- a/src/archive/filesystem_node.cc
+++ b/src/archive/filesystem_node.cc
@@ -115,9 +115,10 @@ PlatformResult Node::resolve(const PathPtr& path, NodePtr* node) {
struct stat syminfo;
if (lstat(path->getFullPath().c_str(), &info) != 0) {
- LoggerE("File:[%s] error no:%d", path->getFullPath().c_str(), errno);
+ int tmp_errno = errno;
+ LoggerE("File: [%s] error no: %d", path->getFullPath().c_str(), tmp_errno);
- switch (errno) {
+ switch (tmp_errno) {
case EACCES:
SLoggerE("File: [%s]", path->getFullPath().c_str());
return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Node access denied");
@@ -147,7 +148,7 @@ PlatformResult Node::resolve(const PathPtr& path, NodePtr* node) {
}
type = S_ISDIR(syminfo.st_mode) ? NT_DIRECTORY : NT_FILE;
- LoggerD("%x", type);
+ LoggerD("%d", type);
}
*node = std::shared_ptr<Node>(new Node(path, type));
diff --git a/src/archive/un_zip.cc b/src/archive/un_zip.cc
index 9689622f..b381bdd4 100644
--- a/src/archive/un_zip.cc
+++ b/src/archive/un_zip.cc
@@ -51,7 +51,7 @@ UnZip::UnZip(const std::string& filename)
UnZip::~UnZip() {
ScopeLogger();
for (auto& x : path_access_map) {
- LoggerD("Setting permission for path: %s [%d] ", x.first.c_str(), x.second);
+ LoggerD("Setting permission for path: %s [%u] ", x.first.c_str(), x.second);
if (chmod(x.first.c_str(), x.second) == -1) {
LoggerE("Couldn't set permissions for: [%s] errno: %s", x.first.c_str(),
GetErrorString(errno).c_str());
diff --git a/src/archive/un_zip_extract_request.cc b/src/archive/un_zip_extract_request.cc
index 3cb09566..1fdd4907 100644
--- a/src/archive/un_zip_extract_request.cc
+++ b/src/archive/un_zip_extract_request.cc
@@ -297,7 +297,7 @@ PlatformResult UnZipExtractRequest::handleDirectoryEntry() {
}
}
- LoggerD("Set dir: [%s] access and modify to: %4d-%2d-%2d %2d:%2d:%2d", m_new_dir_path.c_str(),
+ LoggerD("Set dir: [%s] access and modify to: %4u-%2u-%2u %2u:%2u:%2u", m_new_dir_path.c_str(),
m_file_info.tmu_date.tm_year, m_file_info.tmu_date.tm_mon, m_file_info.tmu_date.tm_mday,
m_file_info.tmu_date.tm_hour, m_file_info.tmu_date.tm_min, m_file_info.tmu_date.tm_sec);
diff --git a/src/archive/zip_add_request.cc b/src/archive/zip_add_request.cc
index bbf823ca..78840c6d 100644
--- a/src/archive/zip_add_request.cc
+++ b/src/archive/zip_add_request.cc
@@ -370,7 +370,7 @@ PlatformResult ZipAddRequest::addToZipArchive(filesystem::NodePtr src_file_node)
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Reading input file failed",
("fseek failed with error! [%d]", res));
}
- LoggerD("Source file: [%s] size: %d - %s", src_file_path.c_str(), in_file_size,
+ LoggerD("Source file: [%s] size: %zu - %s", src_file_path.c_str(), in_file_size,
bytesToReadableString(in_file_size).c_str());
cur_afentry->setSize(in_file_size);
@@ -392,7 +392,7 @@ PlatformResult ZipAddRequest::addToZipArchive(filesystem::NodePtr src_file_node)
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "New file addition failed");
}
- LoggerD("Read: %d bytes from input file:[%s]", size_read, src_file_path.c_str());
+ LoggerD("Read: %zu bytes from input file:[%s]", size_read, src_file_path.c_str());
total_bytes_read += size_read;
m_bytes_compressed += size_read;
@@ -411,7 +411,7 @@ PlatformResult ZipAddRequest::addToZipArchive(filesystem::NodePtr src_file_node)
LoggerD(
"Callculatting overall progress: %llu/%llu bytes; "
- "%lu/%lu files; current file: [%s] progress: %d/%d bytes; ",
+ "%lu/%lu files; current file: [%s] progress: %zu/%zu bytes; ",
m_bytes_compressed, m_bytes_to_compress, m_files_compressed, m_files_to_compress,
src_file_path.c_str(), total_bytes_read, in_file_size);
@@ -432,7 +432,7 @@ PlatformResult ZipAddRequest::addToZipArchive(filesystem::NodePtr src_file_node)
if (in_file_size != total_bytes_read) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Could not add file to archive",
- ("in_file_size(%d) != total_bytes_read(%d)", in_file_size, total_bytes_read));
+ ("in_file_size(%zu) != total_bytes_read(%zu)", in_file_size, total_bytes_read));
}
fclose(m_input_file);
diff --git a/src/badge/badge_manager.cc b/src/badge/badge_manager.cc
index fab178e6..b41f9cc2 100644
--- a/src/badge/badge_manager.cc
+++ b/src/badge/badge_manager.cc
@@ -88,7 +88,7 @@ PlatformResult BadgeManager::SetBadgeCount(const std::string &app_id, unsigned i
}
ret = badge_set_count(app_id_str, count);
- LoggerD("badge_set_count() ret : %d, %s, count : %d ", ret, get_error_message(ret), count);
+ LoggerD("badge_set_count() ret : %d, %s, count : %u ", ret, get_error_message(ret), count);
if (ret == BADGE_ERROR_PERMISSION_DENIED) {
return LogAndCreateResult(ErrorCode::SECURITY_ERR, "Security error");
@@ -136,7 +136,7 @@ PlatformResult BadgeManager::GetBadgeCount(const std::string &app_id, unsigned i
ret = badge_get_count(app_id.c_str(), count);
- LoggerD("badge_get_count() ret : %d count : %d", ret, *count);
+ LoggerD("badge_get_count() ret : %d count : %u", ret, *count);
switch (ret) {
case BADGE_ERROR_NONE:
diff --git a/src/bluetooth/bluetooth_api.js b/src/bluetooth/bluetooth_api.js
index 7a6540a8..c229e6cc 100755
--- a/src/bluetooth/bluetooth_api.js
+++ b/src/bluetooth/bluetooth_api.js
@@ -150,7 +150,7 @@ var BluetoothClassDeviceService = function() {
});
};
-//class tizen.BluetoothLEServiceData //////////////////////
+//class tizen.BluetoothLEServiceData //////////////////////////
tizen.BluetoothLEServiceData = function(d) {
AV.isConstructorCall(this, tizen.BluetoothLEServiceData);
var uuid_ = '';
@@ -191,7 +191,7 @@ tizen.BluetoothLEServiceData = function(d) {
}
};
-//class BluetoothLEAdvertiseData //////////////////////
+//class BluetoothLEAdvertiseData //////////////////////////
tizen.BluetoothLEAdvertiseData = function(dict) {
AV.isConstructorCall(this, tizen.BluetoothLEAdvertiseData);
var includeName_ = false;
@@ -370,7 +370,7 @@ tizen.BluetoothLEAdvertiseData = function(dict) {
}
};
-//class tizen.BluetoothLEManufacturerData //////////////////////
+//class tizen.BluetoothLEManufacturerData //////////////////////////
tizen.BluetoothLEManufacturerData = function(d) {
AV.isConstructorCall(this, tizen.BluetoothLEManufacturerData);
var id_ = '';
@@ -411,7 +411,7 @@ tizen.BluetoothLEManufacturerData = function(d) {
}
};
-// class BluetoothClass //////////////////////
+// class BluetoothClass //////////////////////////
var BluetoothClass = function(data) {
var services = [];
if (data) {
@@ -459,7 +459,7 @@ BluetoothClass.prototype.hasService = function() {
return BluetoothClass_hasService.apply(this, arguments);
};
-// class BluetoothSocket //////////////////////
+// class BluetoothSocket //////////////////////////
var _BLUETOOTH_SOCKET_STATE_CLOSED = 'CLOSED';
function BluetoothSocketListeners() {
@@ -590,7 +590,7 @@ BluetoothSocket.prototype.close = function() {
}
};
-//class BluetoothLEDevice //////////////////////
+//class BluetoothLEDevice //////////////////////////
var BluetoothLEDevice = function(data) {
var address = '',
name = null,
@@ -803,7 +803,7 @@ BluetoothLEDevice.prototype.removeConnectStateChangeListener = function() {
_bleConnectChangeListener.removeListener(args.watchID);
};
-// class BluetoothDevice //////////////////////
+// class BluetoothDevice //////////////////////////
var BluetoothDevice = function(data) {
var self = this;
function _getter(field) {
@@ -913,7 +913,7 @@ BluetoothDevice.prototype.connectToServiceByUUID = function() {
}
};
-// class BluetoothServiceHandler //////////////////////
+// class BluetoothServiceHandler //////////////////////////
function BluetoothServiceListeners() {
var that = this;
this.serviceCallback = function(data) {
@@ -1016,7 +1016,7 @@ BluetoothServiceHandler.prototype.unregister = function() {
_bluetoothServiceListeners.removeListener(this.uuid);
};
-// class BluetoothHealthApplication //////////////////////
+// class BluetoothHealthApplication //////////////////////////
function BluetoothHealthApplicationListeners() {
var that = this;
this.appCallback = function(data) {
@@ -1110,7 +1110,7 @@ BluetoothHealthApplication.prototype.unregister = function() {
_bluetoothHealthApplicationListeners.removeListener(this._id);
};
-// class BluetoothProfileHandler //////////////////////
+// class BluetoothProfileHandler //////////////////////////
var _BluetoothProfileType = {
HEALTH: 'HEALTH'
};
@@ -1123,7 +1123,7 @@ var BluetoothProfileHandler = function(data) {
}
};
-// class BluetoothHealthProfileHandler //////////////////////
+// class BluetoothHealthProfileHandler //////////////////////////
var BluetoothHealthProfileHandler = function(data) {
BluetoothProfileHandler.call(this, data);
};
@@ -1233,7 +1233,7 @@ BluetoothHealthProfileHandler.prototype.connectToSource = function() {
}
};
-// class BluetoothHealthChannel //////////////////////
+// class BluetoothHealthChannel //////////////////////////
var BluetoothHealthChannel = function(data) {
Object.defineProperties(this, {
peer: { value: data.peer, writable: false, enumerable: true },
@@ -1379,8 +1379,8 @@ BluetoothHealthChannel.prototype.unsetListener = function() {
* @param {string} name - name of the listener this manager handles
* @param {function} callback - function to be invoked when event specified by the name
* fires.
- * This function should return false if the callback doesn't
- * want to handle the event anymore, true otherwise.
+ * This function should return false if the callback
+ * doesn't want to handle the event anymore, true otherwise.
* This function should have following signature:
* bool callback(event, successCallback, errorCallback);
*
@@ -1484,7 +1484,7 @@ var _bleAdvertiseListener = _singleListenerBuilder(
}
);
-//class BluetoothLEAdapter //////////////////////
+//class BluetoothLEAdapter //////////////////////////
var BluetoothLEAdapter = function() {};
BluetoothLEAdapter.prototype.startScan = function() {
@@ -1598,7 +1598,7 @@ BluetoothLEAdapter.prototype.stopAdvertise = function() {
}
};
-//class BluetoothGATTService //////////////////////
+//class BluetoothGATTService //////////////////////////
var BluetoothGATTService = function(data, address) {
var handle_ = data.handle;
var uuid_ = data.uuid;
@@ -1653,7 +1653,7 @@ var toByteArray = function(array) {
return d;
};
-//class BluetoothGATTCharacteristic //////////////////////
+//class BluetoothGATTCharacteristic //////////////////////////
var BluetoothGATTCharacteristic = function(data, address) {
var handle_ = data.handle;
var descriptors_ = [];
@@ -1988,7 +1988,7 @@ var _bleConnectChangeListener = _multipleListenerBuilder(
'BluetoothLEDevice_removeConnectStateChangeListener'
);
-//class BluetoothGATTDescriptor //////////////////////
+//class BluetoothGATTDescriptor //////////////////////////
var BluetoothGATTDescriptor = function(data, address) {
var handle_ = data.handle;
//address_ is needed to control if device is still connected
@@ -2071,7 +2071,7 @@ var BluetoothGATTDescriptor = function(data, address) {
};
};
-// class BluetoothAdapter //////////////////////
+// class BluetoothAdapter //////////////////////////
var BluetoothAdapter = function() {
function nameGetter() {
var result = native.callSync('BluetoothAdapter_getName', {});
@@ -2179,9 +2179,9 @@ BluetoothAdapter.prototype.setName = function() {
BluetoothAdapter.prototype.setPowered = function() {
privUtils_.log('Entered BluetoothAdapter.setPowered()');
privUtils_.warn(
- 'DEPRECATION WARNING: setPowered() is deprecated ' +
- 'and will be removed from next release. ' +
- 'Let the user turn on/off Bluetooth through the Settings application instead.'
+ 'DEPRECATION WARNING: setPowered() is deprecated and will be removed from ' +
+ 'next release. Let the user turn on/off Bluetooth through the Settings ' +
+ 'application instead.'
);
var args = AV.validateMethod(arguments, [
@@ -2225,10 +2225,9 @@ BluetoothAdapter.prototype.setPowered = function() {
BluetoothAdapter.prototype.setVisible = function() {
privUtils_.log('Entered BluetoothAdapter.setVisible()');
privUtils_.warn(
- 'DEPRECATION WARNING: setVisible() is deprecated ' +
- 'and will be removed from next release. ' +
- 'Let the user change the Bluetooth visibility through ' +
- 'the Settings application instead.'
+ 'DEPRECATION WARNING: setVisible() is deprecated and will be removed from ' +
+ 'next release. Let the user change the Bluetooth visibility through the ' +
+ 'Settings application instead.'
);
var args = AV.validateMethod(arguments, [
@@ -2698,7 +2697,7 @@ BluetoothAdapter.prototype.getBluetoothProfileHandler = function() {
}
};
-// class BluetoothManager //////////////////////
+// class BluetoothManager //////////////////////////
var BluetoothManager = function() {
Object.defineProperties(this, {
deviceMajor: {
@@ -2748,5 +2747,5 @@ BluetoothManager.prototype.getLEAdapter = function() {
privUtils_.log('Entered BluetoothManager.getLEAdapter()');
return BluetoothManager_getLEAdapter();
};
-// exports /////////////////////////////////////
+// exports /////////////////////////////////////////
exports = new BluetoothManager();
diff --git a/src/calendar/calendar_item.cc b/src/calendar/calendar_item.cc
index 99109bc3..b3bc59d5 100644
--- a/src/calendar/calendar_item.cc
+++ b/src/calendar/calendar_item.cc
@@ -123,14 +123,14 @@ const PlatformEnumMap CalendarItem::platform_enum_map_ = {
{{kDefaultEnumKey, CALENDAR_EVENT_BUSY_STATUS_BUSY},
{"FREE", CALENDAR_EVENT_BUSY_STATUS_FREE},
{"BUSY", CALENDAR_EVENT_BUSY_STATUS_BUSY},
- {"BUSY-UNAVAILABLE", CALENDAR_EVENT_BUSY_STATUS_UNAVAILABLE},
- {"BUSY-TENTATIVE", CALENDAR_EVENT_BUSY_STATUS_TENTATIVE}}},
+ {"BUSY_UNAVAILABLE", CALENDAR_EVENT_BUSY_STATUS_UNAVAILABLE},
+ {"BUSY_TENTATIVE", CALENDAR_EVENT_BUSY_STATUS_TENTATIVE}}},
{kEventAvailability,
{{kDefaultEnumKey, CALENDAR_EVENT_BUSY_STATUS_BUSY},
{"FREE", CALENDAR_EVENT_BUSY_STATUS_FREE},
{"BUSY", CALENDAR_EVENT_BUSY_STATUS_BUSY},
- {"BUSY-UNAVAILABLE", CALENDAR_EVENT_BUSY_STATUS_UNAVAILABLE},
- {"BUSY-TENTATIVE", CALENDAR_EVENT_BUSY_STATUS_TENTATIVE}}},
+ {"BUSY_UNAVAILABLE", CALENDAR_EVENT_BUSY_STATUS_UNAVAILABLE},
+ {"BUSY_TENTATIVE", CALENDAR_EVENT_BUSY_STATUS_TENTATIVE}}},
{kEventPriority,
{{kDefaultEnumKey, CALENDAR_EVENT_PRIORITY_NONE},
{"NONE", CALENDAR_EVENT_PRIORITY_NONE},
@@ -829,7 +829,7 @@ PlatformResult CalendarItem::AttendeesToJson(int type, calendar_record_h rec,
calendar_record_h attendee;
for (unsigned int i = 0; i < count; ++i) {
- LoggerD("Processing the attendee %d", i);
+ LoggerD("Processing the attendee %u", i);
if (GetChildRecordAt(rec, property, &attendee, i).IsError()) {
LoggerW("Can't get attendee record");
@@ -1049,7 +1049,7 @@ PlatformResult CalendarItem::AlarmsToJson(int type, calendar_record_h rec, picoj
int tick, tick_unit;
calendar_record_h alarm;
for (unsigned int i = 0; i < count; ++i) {
- LoggerD("Processing the alarm %d", i);
+ LoggerD("Processing the alarm %u", i);
if (GetChildRecordAt(rec, property, &alarm, i).IsError()) {
LoggerW("Can't get alarm record");
diff --git a/src/calendar/js/calendar.js b/src/calendar/js/calendar.js
index 6269df69..0aede5ee 100755
--- a/src/calendar/js/calendar.js
+++ b/src/calendar/js/calendar.js
@@ -720,8 +720,8 @@ var Calendar_removeChangeListener = function() {
if (type_.isEmptyObject(_listeners)) {
var result;
- // @todo consider listener unregister when we are not listening
- // on this.type of calendar
+ // @todo consider listener unregister when we are not listening on
+ // this.type of calendar
var fail = false;
for (var listenerId in _nativeListeners) {
if (_nativeListeners.hasOwnProperty(listenerId)) {
diff --git a/src/calendar/js/calendar_item.js b/src/calendar/js/calendar_item.js
index 38d1142d..8f2ad6ea 100644
--- a/src/calendar/js/calendar_item.js
+++ b/src/calendar/js/calendar_item.js
@@ -46,7 +46,9 @@ var CalendarItemStatus = {
var EventAvailability = {
BUSY: 'BUSY', //default for CalendarEvent
- FREE: 'FREE'
+ FREE: 'FREE',
+ BUSY_UNAVAILABLE: 'BUSY_UNAVAILABLE',
+ BUSY_TENTATIVE: 'BUSY_TENTATIVE'
};
var CalendarEventId = function(uid, rid) {
@@ -236,16 +238,15 @@ var CalendarItem = function(data) {
: this.dueDate;
}
_duration = v instanceof tizen.TimeDuration ? v : null;
- /*
- @todo Fix UTC, UTC expect duration value but according to documentation:
- ... the implementation may not save the duration itself,
- rather convert it to the corresponding endDate/dueDate attribute and
- save it. For example, if you set the startDate and the duration attributes
- and save the item, you may see that the duration is null while
- endDate/dueDate is non-null after retrieving it because the implementation
- has calculated the endDate/dueDate based on the duration and the startDate
- then saved it, not the duration.
- */
+ //@todo Fix UTC, UTC expect duration value but according to
+ // documentation:
+ // ... the implementation may not save the duration itself,
+ // rather convert it to the corresponding endDate/dueDate attribute and
+ // save it. For example, if you set the startDate and the duration
+ // attributes and save the item, you may see that the duration is null
+ // while endDate/dueDate is non-null after retrieving it because the
+ // implementation has calculated the endDate/dueDate based on the
+ // duration and the startDate then saved it, not the duration.
},
enumerable: true
},
diff --git a/src/callhistory/callhistory.cc b/src/callhistory/callhistory.cc
index 1108c80d..9b610577 100644
--- a/src/callhistory/callhistory.cc
+++ b/src/callhistory/callhistory.cc
@@ -291,7 +291,7 @@ void CallHistory::LoadPhoneNumbers(const picojson::object& args, CallHistory* ca
LoggerD("wait...");
fut.wait();
n = fut.get();
- LoggerD("Phone number [%d] : %s", modem_num, n.c_str());
+ LoggerD("Phone number [%u] : %s", modem_num, n.c_str());
} while (false);
phone_numbers.push_back(n);
@@ -305,11 +305,11 @@ void CallHistory::LoadPhoneNumbers(const picojson::object& args, CallHistory* ca
void CallHistory::find(const picojson::object& args) {
ScopeLogger();
- std::thread([args, this]() {
- ScopeLogger("Entered into asynchronus function, std::thread's argument");
+ common::TaskQueue::GetInstance().Async([args, this]() {
+ ScopeLogger("Entered into asynchronus function");
LoadPhoneNumbers(args, this);
FindThread(args, this);
- }).detach();
+ });
}
PlatformResult CallHistory::remove(const picojson::object& args) {
diff --git a/src/common/GDBus/proxy.cpp b/src/common/GDBus/proxy.cpp
index 86d4d6fa..4b330fd1 100644
--- a/src/common/GDBus/proxy.cpp
+++ b/src/common/GDBus/proxy.cpp
@@ -90,7 +90,7 @@ void Proxy::signalSubscribe() {
m_signal_name.c_str(), m_signal_path.c_str(), NULL,
G_DBUS_SIGNAL_FLAGS_NONE, signalCallbackProxy,
static_cast<gpointer>(this), NULL);
- LoggerD("g_dbus_connection_signal_subscribe returned id: %d", m_sub_id);
+ LoggerD("g_dbus_connection_signal_subscribe returned id: %u", m_sub_id);
m_dbus_signal_subscribed = true;
}
diff --git a/src/common/common.gyp b/src/common/common.gyp
index ff428eed..c3b685cd 100644
--- a/src/common/common.gyp
+++ b/src/common/common.gyp
@@ -34,9 +34,12 @@
'task-queue.h',
'tools.cc',
'tools.h',
+ 'worker.cc',
+ 'worker.h',
'optional.h',
'platform_result.cc',
'platform_result.h',
+ 'platform_enum.h',
'assert.h',
'GDBus/connection.cpp',
'GDBus/connection.h',
@@ -117,6 +120,7 @@
],
},
},
+ 'defines': ['PICOJSON_USE_RVALUE_REFERENCE'],
},
],
}
diff --git a/src/common/common.gypi b/src/common/common.gypi
index cf4fed83..4609a66f 100644
--- a/src/common/common.gypi
+++ b/src/common/common.gypi
@@ -82,6 +82,7 @@
'-fvisibility=hidden',
'-Wall',
'-Werror',
+ '-Wformat-signedness',
],
'cflags_c': [
'-std=c11',
diff --git a/src/common/extension.cc b/src/common/extension.cc
index 53477601..9fc1547b 100644
--- a/src/common/extension.cc
+++ b/src/common/extension.cc
@@ -218,26 +218,36 @@ int32_t Extension::XW_Initialize(XW_Extension extension, XW_GetInterface get_int
return XW_OK;
}
+std::mutex Instance::instances_mutex_;
std::unordered_set<Instance*> Instance::all_instances_;
Instance::Instance() : xw_instance_(0) {
ScopeLogger();
- { all_instances_.insert(this); }
+ {
+ std::lock_guard<std::mutex> lock{instances_mutex_};
+ all_instances_.insert(this);
+ }
}
Instance::~Instance() {
ScopeLogger();
- { all_instances_.erase(this); }
+ {
+ std::lock_guard<std::mutex> lock{instances_mutex_};
+ all_instances_.erase(this);
+ }
Assert(xw_instance_ == 0);
}
void Instance::PostMessage(Instance* that, const char* msg) {
ScopeLogger();
- if (that && all_instances_.end() != all_instances_.find(that)) {
- that->PostMessage(msg);
- } else {
- LoggerE("Trying to post message to non-existing instance: [%p], ignoring", that);
+ if (nullptr != that) {
+ std::lock_guard<std::mutex> lock{instances_mutex_};
+ if (all_instances_.end() != all_instances_.find(that)) {
+ that->PostMessage(msg);
+ return;
+ }
}
+ LoggerE("Trying to post message to non-existing instance: [%p], ignoring", that);
}
void Instance::PostMessage(const char* msg) {
@@ -335,6 +345,7 @@ void ParsedInstance::HandleMessage(const char* msg, bool is_sync) {
auto it = handler_map_.find(cmd);
if (handler_map_.end() == it) {
+ LoggerE("Unknown command: %s", cmd.c_str());
throw UnknownException("Unknown command.");
}
diff --git a/src/common/extension.h b/src/common/extension.h
index 907d1df3..9bb16f40 100644
--- a/src/common/extension.h
+++ b/src/common/extension.h
@@ -21,6 +21,7 @@
#include <functional>
#include <map>
+#include <mutex>
#include <string>
#include <unordered_set>
@@ -109,6 +110,7 @@ class Instance {
private:
friend class Extension;
+ static std::mutex instances_mutex_;
static std::unordered_set<Instance*> all_instances_;
XW_Instance xw_instance_;
diff --git a/src/common/logger.h b/src/common/logger.h
index 3410dd85..228c871b 100644
--- a/src/common/logger.h
+++ b/src/common/logger.h
@@ -7,6 +7,32 @@
#include <dlog.h>
+#ifdef TIZEN_DEBUG_ENABLE
+// Using static inline function with no operation inside to cause compiler types check.
+// Using empty do {} while in WEBAPI_CHECK_PRINTF_FORMAT_ARGS macro will cause that when
+// TIZEN_DEBUG_ENABLE flag is turned off, then no types checking will be performed. This could cause
+// problems when developing code with this flag off and then enabling it.
+static inline int _printf_format_checker(const char* fmt, ...)
+ __attribute__((format(printf, 1, 2)));
+
+int _printf_format_checker(const char* fmt, ...) {
+ return 0;
+}
+
+#define WEBAPI_CHECK_PRINTF_FORMAT_ARGS(...) \
+ ({ \
+ do { \
+ _printf_format_checker(__VA_ARGS__); \
+ } while (0); \
+ })
+
+#else // TIZEN_DEBUG_ENABLE
+
+#define WEBAPI_NOOP() \
+ do { \
+ } while (0);
+#endif // TIZEN_DEBUG_ENABLE
+
// Tizen 3.0 uses different debug flag (DLOG_DEBUG_ENABLE) which is always
// enabled, following code allows to disable logs with DLOG_DEBUG priority if
// TIZEN_DEBUG_ENABLE is not set.
@@ -17,6 +43,7 @@
#define LOG_(id, prio, tag, fmt, arg...) \
({ \
do { \
+ WEBAPI_CHECK_PRINTF_FORMAT_ARGS(fmt, ##arg); \
__dlog_print(id, prio, tag, "%s: %s(%d) > " fmt, __MODULE__, __func__, __LINE__, ##arg); \
} while (0); \
})
@@ -36,12 +63,13 @@
#define SECURE_LOG_(id, prio, tag, fmt, arg...) \
({ \
do { \
+ WEBAPI_CHECK_PRINTF_FORMAT_ARGS(fmt, ##arg); \
__dlog_print(id, prio, tag, "%s: %s(%d) > [SECURE_LOG] " fmt, __MODULE__, __func__, \
__LINE__, ##arg); \
} while (0); \
})
#else // TIZEN_DEBUG_ENABLE
-#define SECURE_LOG_(id, prio, tag, fmt, arg...) NOP(fmt, ##arg)
+#define SECURE_LOG_(id, prio, tag, fmt, arg...) WEBAPI_NOOP()
#endif // TIZEN_DEBUG_ENABLE
#include <cstring>
@@ -247,13 +275,14 @@ class ScopeLogger {
#ifdef TIZEN_DEBUG_ENABLE
#define ScopeLogger(EX, args...) \
+ WEBAPI_CHECK_PRINTF_FORMAT_ARGS("noop" EX, ##args); \
__dlog_print(LOG_ID_MAIN, DLOG_DEBUG, LOGGER_TAG, \
"logger.h: ScopeLogger > %s: %s(%d) > Enter " EX, __MODULE__, __func__, __LINE__, \
##args); \
const common::ScopeLogger __sl__{__MODULE__, __func__};
#else
-#define ScopeLogger(EX, args...)
+#define ScopeLogger(EX, args...) WEBAPI_NOOP()
#endif
#endif // COMMON_LOGGER_H_
diff --git a/src/common/picojson.h b/src/common/picojson.h
index 44ae5431..c6b9aded 100644
--- a/src/common/picojson.h
+++ b/src/common/picojson.h
@@ -1,60 +1,116 @@
/*
* Copyright 2009-2010 Cybozu Labs, Inc.
- * Copyright 2011 Kazuho Oku
+ * Copyright 2011-2014 Kazuho Oku
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
+ *
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY CYBOZU LABS, INC. ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL CYBOZU LABS, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are
- * those of the authors and should not be interpreted as representing official
- * policies, either expressed or implied, of Cybozu Labs, Inc.
- *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef picojson_h
#define picojson_h
#include <algorithm>
-#include <cmath>
+#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <iterator>
+#include <limits>
#include <map>
+#include <memory>
#include <sstream>
+#include <stdexcept>
#include <string>
+#include <utility>
#include <vector>
#include "common/assert.h"
+// for isnan/isinf
+#if __cplusplus >= 201103L
+#include <cmath>
+#else
+extern "C" {
+#ifdef _MSC_VER
+#include <float.h>
+#elif defined(__INTEL_COMPILER)
+#include <mathimf.h>
+#else
+#include <math.h>
+#endif
+}
+#endif
+
+#ifndef PICOJSON_USE_RVALUE_REFERENCE
+#if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || \
+ (defined(_MSC_VER) && _MSC_VER >= 1600)
+#define PICOJSON_USE_RVALUE_REFERENCE 1
+#else
+#define PICOJSON_USE_RVALUE_REFERENCE 0
+#endif
+#endif // PICOJSON_USE_RVALUE_REFERENCE
+
+#ifndef PICOJSON_NOEXCEPT
+#if PICOJSON_USE_RVALUE_REFERENCE
+#define PICOJSON_NOEXCEPT noexcept
+#else
+#define PICOJSON_NOEXCEPT throw()
+#endif
+#endif
+
+// experimental support for int64_t (see README.mkdn for detail)
+#ifdef PICOJSON_USE_INT64
+#define __STDC_FORMAT_MACROS
+#include <errno.h>
+#include <inttypes.h>
+#endif
+
#ifdef _MSC_VER
#define SNPRINTF _snprintf_s
#pragma warning(push)
#pragma warning(disable : 4244) // conversion from int to char
+#pragma warning(disable : 4127) // conditional expression is constant
+#pragma warning(disable : 4702) // unreachable code
#else
#define SNPRINTF snprintf
#endif
namespace picojson {
-enum { null_type, boolean_type, number_type, string_type, array_type, object_type };
+enum {
+ null_type,
+ boolean_type,
+ number_type,
+ string_type,
+ array_type,
+ object_type
+#ifdef PICOJSON_USE_INT64
+ ,
+ int64_type
+#endif
+};
+
+enum { INDENT_WIDTH = 2 };
struct null {};
@@ -65,9 +121,12 @@ class value {
union _storage {
bool boolean_;
double number_;
- std::string* string_;
- array* array_;
- object* object_;
+#ifdef PICOJSON_USE_INT64
+ int64_t int64_;
+#endif
+ std::string *string_;
+ array *array_;
+ object *object_;
};
protected:
@@ -78,44 +137,71 @@ class value {
value();
value(int type, bool);
explicit value(bool b);
+#ifdef PICOJSON_USE_INT64
+ explicit value(int64_t i);
+#endif
explicit value(double n);
- explicit value(const std::string& s);
- explicit value(const array& a);
- explicit value(const object& o);
- explicit value(const char* s);
- value(const char* s, size_t len);
+ explicit value(const std::string &s);
+ explicit value(const array &a);
+ explicit value(const object &o);
+#if PICOJSON_USE_RVALUE_REFERENCE
+ explicit value(std::string &&s);
+ explicit value(array &&a);
+ explicit value(object &&o);
+#endif
+ explicit value(const char *s);
+ value(const char *s, size_t len);
~value();
- value(const value& x);
- value& operator=(const value& x);
- void swap(value& x);
+ value(const value &x);
+ value &operator=(const value &x);
+#if PICOJSON_USE_RVALUE_REFERENCE
+ value(value &&x) PICOJSON_NOEXCEPT;
+ value &operator=(value &&x) PICOJSON_NOEXCEPT;
+#endif
+ void swap(value &x) PICOJSON_NOEXCEPT;
template <typename T>
bool is() const;
template <typename T>
- const T& get() const;
+ const T &get() const;
+ template <typename T>
+ T &get();
template <typename T>
- T& get();
+ void set(const T &);
+#if PICOJSON_USE_RVALUE_REFERENCE
+ template <typename T>
+ void set(T &&);
+#endif
bool evaluate_as_boolean() const;
- const value& get(size_t idx) const;
- const value& get(const std::string& key) const;
- bool contains(size_t idx) const;
- bool contains(const std::string& key) const;
+ const value &get(const size_t idx) const;
+ const value &get(const std::string &key) const;
+ value &get(const size_t idx);
+ value &get(const std::string &key);
+
+ bool contains(const size_t idx) const;
+ bool contains(const std::string &key) const;
std::string to_str() const;
template <typename Iter>
- void serialize(Iter os) const;
- std::string serialize() const;
+ void serialize(Iter os, bool prettify = false) const;
+ std::string serialize(bool prettify = false) const;
private:
template <typename T>
- value(const T*); // intentionally defined to block implicit conversion of pointer to bool
+ value(const T *); // intentionally defined to block implicit conversion of pointer to bool
+ template <typename Iter>
+ static void _indent(Iter os, int indent);
+ template <typename Iter>
+ void _serialize(Iter os, int indent) const;
+ std::string _serialize(int indent) const;
+ void clear();
};
typedef value::array array;
typedef value::object object;
-inline value::value() : type_(null_type) {
+inline value::value() : type_(null_type), u_() {
}
-inline value::value(int type, bool) : type_(type) {
+inline value::value(int type, bool) : type_(type), u_() {
switch (type) {
#define INIT(p, v) \
case p##type: \
@@ -123,6 +209,9 @@ inline value::value(int type, bool) : type_(type) {
break
INIT(boolean_, false);
INIT(number_, 0.0);
+#ifdef PICOJSON_USE_INT64
+ INIT(int64_, 0);
+#endif
INIT(string_, new std::string());
INIT(array_, new array());
INIT(object_, new object());
@@ -132,35 +221,66 @@ inline value::value(int type, bool) : type_(type) {
}
}
-inline value::value(bool b) : type_(boolean_type) {
+inline value::value(bool b) : type_(boolean_type), u_() {
u_.boolean_ = b;
}
-inline value::value(double n) : type_(number_type) {
+#ifdef PICOJSON_USE_INT64
+inline value::value(int64_t i) : type_(int64_type), u_() {
+ u_.int64_ = i;
+}
+#endif
+
+inline value::value(double n) : type_(number_type), u_() {
+ if (
+#ifdef _MSC_VER
+ !_finite(n)
+#elif __cplusplus >= 201103L
+ std::isnan(n) || std::isinf(n)
+#else
+ isnan(n) || isinf(n)
+#endif
+ ) {
+ throw std::overflow_error("");
+ }
u_.number_ = n;
}
-inline value::value(const std::string& s) : type_(string_type) {
+inline value::value(const std::string &s) : type_(string_type), u_() {
u_.string_ = new std::string(s);
}
-inline value::value(const array& a) : type_(array_type) {
+inline value::value(const array &a) : type_(array_type), u_() {
u_.array_ = new array(a);
}
-inline value::value(const object& o) : type_(object_type) {
+inline value::value(const object &o) : type_(object_type), u_() {
u_.object_ = new object(o);
}
-inline value::value(const char* s) : type_(string_type) {
+#if PICOJSON_USE_RVALUE_REFERENCE
+inline value::value(std::string &&s) : type_(string_type), u_() {
+ u_.string_ = new std::string(std::move(s));
+}
+
+inline value::value(array &&a) : type_(array_type), u_() {
+ u_.array_ = new array(std::move(a));
+}
+
+inline value::value(object &&o) : type_(object_type), u_() {
+ u_.object_ = new object(std::move(o));
+}
+#endif
+
+inline value::value(const char *s) : type_(string_type), u_() {
u_.string_ = new std::string(s);
}
-inline value::value(const char* s, size_t len) : type_(string_type) {
+inline value::value(const char *s, size_t len) : type_(string_type), u_() {
u_.string_ = new std::string(s, len);
}
-inline value::~value() {
+inline void value::clear() {
switch (type_) {
#define DEINIT(p) \
case p##type: \
@@ -175,7 +295,11 @@ inline value::~value() {
}
}
-inline value::value(const value& x) : type_(x.type_) {
+inline value::~value() {
+ clear();
+}
+
+inline value::value(const value &x) : type_(x.type_), u_() {
switch (type_) {
#define INIT(p, v) \
case p##type: \
@@ -191,15 +315,24 @@ inline value::value(const value& x) : type_(x.type_) {
}
}
-inline value& value::operator=(const value& x) {
+inline value &value::operator=(const value &x) {
if (this != &x) {
- this->~value();
- new (this) value(x);
+ value t(x);
+ swap(t);
}
return *this;
}
-inline void value::swap(value& x) {
+#if PICOJSON_USE_RVALUE_REFERENCE
+inline value::value(value &&x) PICOJSON_NOEXCEPT : type_(null_type), u_() {
+ swap(x);
+}
+inline value &value::operator=(value &&x) PICOJSON_NOEXCEPT {
+ swap(x);
+ return *this;
+}
+#endif
+inline void value::swap(value &x) PICOJSON_NOEXCEPT {
std::swap(type_, x.type_);
std::swap(u_, x.u_);
}
@@ -211,31 +344,78 @@ inline void value::swap(value& x) {
}
IS(null, null)
IS(bool, boolean)
-IS(int, number)
-IS(double, number)
+#ifdef PICOJSON_USE_INT64
+IS(int64_t, int64)
+#endif
IS(std::string, string)
IS(array, array)
IS(object, object)
#undef IS
+template <>
+inline bool value::is<double>() const {
+ return type_ == number_type
+#ifdef PICOJSON_USE_INT64
+ || type_ == int64_type
+#endif
+ ;
+}
-#define GET(ctype, var) \
- template <> \
- inline const ctype& value::get<ctype>() const { \
- Assert("type mismatch! call vis<type>() before get<type>()" && is<ctype>()); \
- return var; \
- } \
- template <> \
- inline ctype& value::get<ctype>() { \
- Assert("type mismatch! call is<type>() before get<type>()" && is<ctype>()); \
- return var; \
+#define GET(ctype, var) \
+ template <> \
+ inline const ctype &value::get<ctype>() const { \
+ Assert("type mismatch! call is<type>() before get<type>()" && is<ctype>()); \
+ return var; \
+ } \
+ template <> \
+ inline ctype &value::get<ctype>() { \
+ Assert("type mismatch! call is<type>() before get<type>()" && is<ctype>()); \
+ return var; \
}
GET(bool, u_.boolean_)
-GET(double, u_.number_)
GET(std::string, *u_.string_)
GET(array, *u_.array_)
GET(object, *u_.object_)
+#ifdef PICOJSON_USE_INT64
+GET(double, (type_ == int64_type && (const_cast<value *>(this)->type_ = number_type,
+ const_cast<value *>(this)->u_.number_ = u_.int64_),
+ u_.number_))
+GET(int64_t, u_.int64_)
+#else
+GET(double, u_.number_)
+#endif
#undef GET
+#define SET(ctype, jtype, setter) \
+ template <> \
+ inline void value::set<ctype>(const ctype &_val) { \
+ clear(); \
+ type_ = jtype##_type; \
+ setter \
+ }
+SET(bool, boolean, u_.boolean_ = _val;)
+SET(std::string, string, u_.string_ = new std::string(_val);)
+SET(array, array, u_.array_ = new array(_val);)
+SET(object, object, u_.object_ = new object(_val);)
+SET(double, number, u_.number_ = _val;)
+#ifdef PICOJSON_USE_INT64
+SET(int64_t, int64, u_.int64_ = _val;)
+#endif
+#undef SET
+
+#if PICOJSON_USE_RVALUE_REFERENCE
+#define MOVESET(ctype, jtype, setter) \
+ template <> \
+ inline void value::set<ctype>(ctype && _val) { \
+ clear(); \
+ type_ = jtype##_type; \
+ setter \
+ }
+MOVESET(std::string, string, u_.string_ = new std::string(std::move(_val));)
+MOVESET(array, array, u_.array_ = new array(std::move(_val));)
+MOVESET(object, object, u_.object_ = new object(std::move(_val));)
+#undef MOVESET
+#endif
+
inline bool value::evaluate_as_boolean() const {
switch (type_) {
case null_type:
@@ -244,6 +424,10 @@ inline bool value::evaluate_as_boolean() const {
return u_.boolean_;
case number_type:
return u_.number_ != 0;
+#ifdef PICOJSON_USE_INT64
+ case int64_type:
+ return u_.int64_ != 0;
+#endif
case string_type:
return !u_.string_->empty();
default:
@@ -251,25 +435,38 @@ inline bool value::evaluate_as_boolean() const {
}
}
-inline const value& value::get(size_t idx) const {
+inline const value &value::get(const size_t idx) const {
+ static value s_null;
+ Assert(is<array>());
+ return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
+}
+
+inline value &value::get(const size_t idx) {
static value s_null;
Assert(is<array>());
return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
}
-inline const value& value::get(const std::string& key) const {
+inline const value &value::get(const std::string &key) const {
static value s_null;
Assert(is<object>());
object::const_iterator i = u_.object_->find(key);
return i != u_.object_->end() ? i->second : s_null;
}
-inline bool value::contains(size_t idx) const {
+inline value &value::get(const std::string &key) {
+ static value s_null;
+ Assert(is<object>());
+ object::iterator i = u_.object_->find(key);
+ return i != u_.object_->end() ? i->second : s_null;
+}
+
+inline bool value::contains(const size_t idx) const {
Assert(is<array>());
return idx < u_.array_->size();
}
-inline bool value::contains(const std::string& key) const {
+inline bool value::contains(const std::string &key) const {
Assert(is<object>());
object::const_iterator i = u_.object_->find(key);
return i != u_.object_->end();
@@ -281,6 +478,13 @@ inline std::string value::to_str() const {
return "null";
case boolean_type:
return u_.boolean_ ? "true" : "false";
+#ifdef PICOJSON_USE_INT64
+ case int64_type: {
+ char buf[sizeof("-9223372036854775808")];
+ SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_);
+ return buf;
+ }
+#endif
case number_type: {
std::stringstream num_str;
num_str.imbue(std::locale::classic());
@@ -303,24 +507,24 @@ inline std::string value::to_str() const {
}
template <typename Iter>
-void copy(const std::string& s, Iter oi) {
+void copy(const std::string &s, Iter oi) {
std::copy(s.begin(), s.end(), oi);
}
template <typename Iter>
-void serialize_str(const std::string& s, Iter oi) {
- // C0 control characters, 00-1F
- static const char* u_map[] = {
- "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007",
- "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f",
- "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017",
- "\\u0018", "\\u0019", "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f"};
- // To be sure we could rewrite C1 control characters also (first decode UTF-8, check, then map to
- // \u sequence), but for now chromium allows C1 in JSON.parse
-
- *oi++ = '"';
- for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
- switch (*i) {
+struct serialize_str_char {
+ Iter oi;
+ void operator()(char c) {
+ // C0 control characters, 00-1F
+ static const char *u_map[] = {
+ "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007",
+ "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f",
+ "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017",
+ "\\u0018", "\\u0019", "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f"};
+ // To be sure we could rewrite C1 control characters also (first decode UTF-8, check, then map
+ // to
+ // \u sequence), but for now chromium allows C1 in JSON.parse
+ switch (c) {
case '"':
copy("\\\"", oi);
break;
@@ -331,46 +535,97 @@ void serialize_str(const std::string& s, Iter oi) {
copy("\\u007f", oi);
break;
default:
- if ((unsigned char)*i < 0x20) {
- const char* u = u_map[(unsigned char)*i];
+ if ((unsigned char)c < 0x20) {
+ const char *u = u_map[(unsigned char)c];
while (*u) {
*oi++ = *u++;
}
} else {
- *oi++ = *i;
+ *oi++ = c;
}
break;
}
}
+};
+
+template <typename Iter>
+void serialize_str(const std::string &s, Iter oi) {
+ *oi++ = '"';
+ serialize_str_char<Iter> process_char = {oi};
+ std::for_each(s.begin(), s.end(), process_char);
*oi++ = '"';
}
template <typename Iter>
-void value::serialize(Iter oi) const {
+void value::serialize(Iter oi, bool prettify) const {
+ return _serialize(oi, prettify ? 0 : -1);
+}
+
+inline std::string value::serialize(bool prettify) const {
+ return _serialize(prettify ? 0 : -1);
+}
+
+template <typename Iter>
+void value::_indent(Iter oi, int indent) {
+ *oi++ = '\n';
+ for (int i = 0; i < indent * INDENT_WIDTH; ++i) {
+ *oi++ = ' ';
+ }
+}
+
+template <typename Iter>
+void value::_serialize(Iter oi, int indent) const {
switch (type_) {
case string_type:
serialize_str(*u_.string_, oi);
break;
case array_type: {
*oi++ = '[';
+ if (indent != -1) {
+ ++indent;
+ }
for (array::const_iterator i = u_.array_->begin(); i != u_.array_->end(); ++i) {
if (i != u_.array_->begin()) {
*oi++ = ',';
}
- i->serialize(oi);
+ if (indent != -1) {
+ _indent(oi, indent);
+ }
+ i->_serialize(oi, indent);
+ }
+ if (indent != -1) {
+ --indent;
+ if (!u_.array_->empty()) {
+ _indent(oi, indent);
+ }
}
*oi++ = ']';
break;
}
case object_type: {
*oi++ = '{';
+ if (indent != -1) {
+ ++indent;
+ }
for (object::const_iterator i = u_.object_->begin(); i != u_.object_->end(); ++i) {
if (i != u_.object_->begin()) {
*oi++ = ',';
}
+ if (indent != -1) {
+ _indent(oi, indent);
+ }
serialize_str(i->first, oi);
*oi++ = ':';
- i->second.serialize(oi);
+ if (indent != -1) {
+ *oi++ = ' ';
+ }
+ i->second._serialize(oi, indent);
+ }
+ if (indent != -1) {
+ --indent;
+ if (!u_.object_->empty()) {
+ _indent(oi, indent);
+ }
}
*oi++ = '}';
break;
@@ -379,11 +634,14 @@ void value::serialize(Iter oi) const {
copy(to_str(), oi);
break;
}
+ if (indent == 0) {
+ *oi++ = '\n';
+ }
}
-inline std::string value::serialize() const {
+inline std::string value::_serialize(int indent) const {
std::string s;
- serialize(std::back_inserter(s));
+ _serialize(std::back_inserter(s), indent);
return s;
}
@@ -391,36 +649,35 @@ template <typename Iter>
class input {
protected:
Iter cur_, end_;
- int last_ch_;
- bool ungot_;
+ bool consumed_;
int line_;
public:
- input(const Iter& first, const Iter& last)
- : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {
+ input(const Iter &first, const Iter &last) : cur_(first), end_(last), consumed_(false), line_(1) {
}
int getc() {
- if (ungot_) {
- ungot_ = false;
- return last_ch_;
+ if (consumed_) {
+ if (*cur_ == '\n') {
+ ++line_;
+ }
+ ++cur_;
}
if (cur_ == end_) {
- last_ch_ = -1;
+ consumed_ = false;
return -1;
}
- if (last_ch_ == '\n') {
- line_++;
- }
- last_ch_ = *cur_++ & 0xff;
- return last_ch_;
+ consumed_ = true;
+ return *cur_ & 0xff;
}
void ungetc() {
- if (last_ch_ != -1) {
- Assert(!ungot_);
- ungot_ = true;
- }
+ consumed_ = false;
}
Iter cur() const {
+ if (consumed_) {
+ input<Iter> *self = const_cast<input<Iter> *>(this);
+ self->consumed_ = false;
+ ++self->cur_;
+ }
return cur_;
}
int line() const {
@@ -435,15 +692,15 @@ class input {
}
}
}
- bool expect(int expect) {
+ bool expect(const int expected) {
skip_ws();
- if (getc() != expect) {
+ if (getc() != expected) {
ungetc();
return false;
}
return true;
}
- bool match(const std::string& pattern) {
+ bool match(const std::string &pattern) {
for (std::string::const_iterator pi(pattern.begin()); pi != pattern.end(); ++pi) {
if (getc() != *pi) {
ungetc();
@@ -455,7 +712,7 @@ class input {
};
template <typename Iter>
-inline int _parse_quadhex(input<Iter>& in) {
+inline int _parse_quadhex(input<Iter> &in) {
int uni_ch = 0, hex;
for (int i = 0; i < 4; i++) {
if ((hex = in.getc()) == -1) {
@@ -477,7 +734,7 @@ inline int _parse_quadhex(input<Iter>& in) {
}
template <typename String, typename Iter>
-inline bool _parse_codepoint(String& out, input<Iter>& in) {
+inline bool _parse_codepoint(String &out, input<Iter> &in) {
int uni_ch;
if ((uni_ch = _parse_quadhex(in)) == -1) {
return false;
@@ -500,26 +757,26 @@ inline bool _parse_codepoint(String& out, input<Iter>& in) {
uni_ch += 0x10000;
}
if (uni_ch < 0x80) {
- out.push_back(uni_ch);
+ out.push_back(static_cast<char>(uni_ch));
} else {
if (uni_ch < 0x800) {
- out.push_back(0xc0 | (uni_ch >> 6));
+ out.push_back(static_cast<char>(0xc0 | (uni_ch >> 6)));
} else {
if (uni_ch < 0x10000) {
- out.push_back(0xe0 | (uni_ch >> 12));
+ out.push_back(static_cast<char>(0xe0 | (uni_ch >> 12)));
} else {
- out.push_back(0xf0 | (uni_ch >> 18));
- out.push_back(0x80 | ((uni_ch >> 12) & 0x3f));
+ out.push_back(static_cast<char>(0xf0 | (uni_ch >> 18)));
+ out.push_back(static_cast<char>(0x80 | ((uni_ch >> 12) & 0x3f)));
}
- out.push_back(0x80 | ((uni_ch >> 6) & 0x3f));
+ out.push_back(static_cast<char>(0x80 | ((uni_ch >> 6) & 0x3f)));
}
- out.push_back(0x80 | (uni_ch & 0x3f));
+ out.push_back(static_cast<char>(0x80 | (uni_ch & 0x3f)));
}
return true;
}
template <typename String, typename Iter>
-inline bool _parse_string(String& out, input<Iter>& in) {
+inline bool _parse_string(String &out, input<Iter> &in) {
while (1) {
int ch = in.getc();
if (ch < ' ') {
@@ -554,32 +811,32 @@ inline bool _parse_string(String& out, input<Iter>& in) {
return false;
}
} else {
- out.push_back(ch);
+ out.push_back(static_cast<char>(ch));
}
}
return false;
}
template <typename Context, typename Iter>
-inline bool _parse_array(Context& ctx, input<Iter>& in) {
+inline bool _parse_array(Context &ctx, input<Iter> &in) {
if (!ctx.parse_array_start()) {
return false;
}
+ size_t idx = 0;
if (in.expect(']')) {
- return true;
+ return ctx.parse_array_stop(idx);
}
- size_t idx = 0;
do {
if (!ctx.parse_array_item(in, idx)) {
return false;
}
idx++;
} while (in.expect(','));
- return in.expect(']');
+ return in.expect(']') && ctx.parse_array_stop(idx);
}
template <typename Context, typename Iter>
-inline bool _parse_object(Context& ctx, input<Iter>& in) {
+inline bool _parse_object(Context &ctx, input<Iter> &in) {
if (!ctx.parse_object_start()) {
return false;
}
@@ -599,13 +856,13 @@ inline bool _parse_object(Context& ctx, input<Iter>& in) {
}
template <typename Iter>
-inline bool _parse_number(double& out, input<Iter>& in) {
+inline std::string _parse_number(input<Iter> &in) {
std::stringstream num_str;
num_str.imbue(std::locale::classic());
while (true) {
int ch = in.getc();
- if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == '.' || ch == 'e' || ch == 'E') {
+ if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == 'e' || ch == 'E' || ch == '.') {
num_str.put(ch);
} else {
in.ungetc();
@@ -613,13 +870,11 @@ inline bool _parse_number(double& out, input<Iter>& in) {
}
}
- num_str >> out;
-
- return num_str && num_str.eof();
+ return num_str.str();
}
template <typename Context, typename Iter>
-inline bool _parse(Context& ctx, input<Iter>& in) {
+inline bool _parse(Context &ctx, input<Iter> &in) {
in.skip_ws();
int ch = in.getc();
switch (ch) {
@@ -642,14 +897,31 @@ inline bool _parse(Context& ctx, input<Iter>& in) {
return _parse_object(ctx, in);
default:
if (('0' <= ch && ch <= '9') || ch == '-') {
- in.ungetc();
double f;
- if (_parse_number(f, in)) {
+ char *endp;
+ in.ungetc();
+ std::string num_str(_parse_number(in));
+ if (num_str.empty()) {
+ return false;
+ }
+#ifdef PICOJSON_USE_INT64
+ {
+ errno = 0;
+ intmax_t ival = strtoimax(num_str.c_str(), &endp, 10);
+ if (errno == 0 && std::numeric_limits<int64_t>::min() <= ival &&
+ ival <= std::numeric_limits<int64_t>::max() &&
+ endp == num_str.c_str() + num_str.size()) {
+ ctx.set_int64(ival);
+ return true;
+ }
+ }
+#endif
+ f = strtod(num_str.c_str(), &endp);
+ if (endp == num_str.c_str() + num_str.size()) {
ctx.set_number(f);
return true;
- } else {
- return false;
}
+ return false;
}
break;
}
@@ -665,35 +937,43 @@ class deny_parse_context {
bool set_bool(bool) {
return false;
}
+#ifdef PICOJSON_USE_INT64
+ bool set_int64(int64_t) {
+ return false;
+ }
+#endif
bool set_number(double) {
return false;
}
template <typename Iter>
- bool parse_string(input<Iter>&) {
+ bool parse_string(input<Iter> &) {
return false;
}
bool parse_array_start() {
return false;
}
template <typename Iter>
- bool parse_array_item(input<Iter>&, size_t) {
+ bool parse_array_item(input<Iter> &, size_t) {
+ return false;
+ }
+ bool parse_array_stop(size_t) {
return false;
}
bool parse_object_start() {
return false;
}
template <typename Iter>
- bool parse_object_item(input<Iter>&, const std::string&) {
+ bool parse_object_item(input<Iter> &, const std::string &) {
return false;
}
};
class default_parse_context {
protected:
- value* out_;
+ value *out_;
public:
- default_parse_context(value* out) : out_(out) {
+ default_parse_context(value *out) : out_(out) {
}
bool set_null() {
*out_ = value();
@@ -703,12 +983,18 @@ class default_parse_context {
*out_ = value(b);
return true;
}
+#ifdef PICOJSON_USE_INT64
+ bool set_int64(int64_t i) {
+ *out_ = value(i);
+ return true;
+ }
+#endif
bool set_number(double f) {
*out_ = value(f);
return true;
}
template <typename Iter>
- bool parse_string(input<Iter>& in) {
+ bool parse_string(input<Iter> &in) {
*out_ = value(string_type, false);
return _parse_string(out_->get<std::string>(), in);
}
@@ -717,26 +1003,29 @@ class default_parse_context {
return true;
}
template <typename Iter>
- bool parse_array_item(input<Iter>& in, size_t) {
- array& a = out_->get<array>();
+ bool parse_array_item(input<Iter> &in, size_t) {
+ array &a = out_->get<array>();
a.push_back(value());
default_parse_context ctx(&a.back());
return _parse(ctx, in);
}
+ bool parse_array_stop(size_t) {
+ return true;
+ }
bool parse_object_start() {
*out_ = value(object_type, false);
return true;
}
template <typename Iter>
- bool parse_object_item(input<Iter>& in, const std::string& key) {
- object& o = out_->get<object>();
+ bool parse_object_item(input<Iter> &in, const std::string &key) {
+ object &o = out_->get<object>();
default_parse_context ctx(&o[key]);
return _parse(ctx, in);
}
private:
- default_parse_context(const default_parse_context&);
- default_parse_context& operator=(const default_parse_context&);
+ default_parse_context(const default_parse_context &);
+ default_parse_context &operator=(const default_parse_context &);
};
class null_parse_context {
@@ -755,11 +1044,16 @@ class null_parse_context {
bool set_bool(bool) {
return true;
}
+#ifdef PICOJSON_USE_INT64
+ bool set_int64(int64_t) {
+ return true;
+ }
+#endif
bool set_number(double) {
return true;
}
template <typename Iter>
- bool parse_string(input<Iter>& in) {
+ bool parse_string(input<Iter> &in) {
dummy_str s;
return _parse_string(s, in);
}
@@ -767,32 +1061,35 @@ class null_parse_context {
return true;
}
template <typename Iter>
- bool parse_array_item(input<Iter>& in, size_t) {
+ bool parse_array_item(input<Iter> &in, size_t) {
return _parse(*this, in);
}
+ bool parse_array_stop(size_t) {
+ return true;
+ }
bool parse_object_start() {
return true;
}
template <typename Iter>
- bool parse_object_item(input<Iter>& in, const std::string&) {
+ bool parse_object_item(input<Iter> &in, const std::string &) {
return _parse(*this, in);
}
private:
- null_parse_context(const null_parse_context&);
- null_parse_context& operator=(const null_parse_context&);
+ null_parse_context(const null_parse_context &);
+ null_parse_context &operator=(const null_parse_context &);
};
// obsolete, use the version below
template <typename Iter>
-inline std::string parse(value& out, Iter& pos, const Iter& last) {
+inline std::string parse(value &out, Iter &pos, const Iter &last) {
std::string err;
pos = parse(out, pos, last, &err);
return err;
}
template <typename Context, typename Iter>
-inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) {
+inline Iter _parse(Context &ctx, const Iter &first, const Iter &last, std::string *err) {
input<Iter> in(first, last);
if (!_parse(ctx, in) && err != NULL) {
char buf[64];
@@ -803,7 +1100,7 @@ inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::strin
if (ch == -1 || ch == '\n') {
break;
} else if (ch >= ' ') {
- err->push_back(ch);
+ err->push_back(static_cast<char>(ch));
}
}
}
@@ -811,12 +1108,18 @@ inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::strin
}
template <typename Iter>
-inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) {
+inline Iter parse(value &out, const Iter &first, const Iter &last, std::string *err) {
default_parse_context ctx(&out);
return _parse(ctx, first, last, err);
}
-inline std::string parse(value& out, std::istream& is) {
+inline std::string parse(value &out, const std::string &s) {
+ std::string err;
+ parse(out, s.begin(), s.end(), &err);
+ return err;
+}
+
+inline std::string parse(value &out, std::istream &is) {
std::string err;
parse(out, std::istreambuf_iterator<char>(is.rdbuf()), std::istreambuf_iterator<char>(), &err);
return err;
@@ -829,15 +1132,15 @@ struct last_error_t {
template <typename T>
std::string last_error_t<T>::s;
-inline void set_last_error(const std::string& s) {
+inline void set_last_error(const std::string &s) {
last_error_t<bool>::s = s;
}
-inline const std::string& get_last_error() {
+inline const std::string &get_last_error() {
return last_error_t<bool>::s;
}
-inline bool operator==(const value& x, const value& y) {
+inline bool operator==(const value &x, const value &y) {
if (x.is<null>()) return y.is<null>();
#define PICOJSON_CMP(type) \
if (x.is<type>()) return y.is<type>() && x.get<type>() == y.get<type>()
@@ -854,21 +1157,23 @@ inline bool operator==(const value& x, const value& y) {
return false;
}
-inline bool operator!=(const value& x, const value& y) {
+inline bool operator!=(const value &x, const value &y) {
return !(x == y);
}
}
+#if !PICOJSON_USE_RVALUE_REFERENCE
namespace std {
template <>
-inline void swap(picojson::value& x, picojson::value& y) {
+inline void swap(picojson::value &x, picojson::value &y) {
x.swap(y);
}
}
+#endif
-inline std::istream& operator>>(std::istream& is, picojson::value& x) {
+inline std::istream &operator>>(std::istream &is, picojson::value &x) {
picojson::set_last_error(std::string());
- std::string err = picojson::parse(x, is);
+ const std::string err(picojson::parse(x, is));
if (!err.empty()) {
picojson::set_last_error(err);
is.setstate(std::ios::failbit);
@@ -876,7 +1181,7 @@ inline std::istream& operator>>(std::istream& is, picojson::value& x) {
return is;
}
-inline std::ostream& operator<<(std::ostream& os, const picojson::value& x) {
+inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) {
x.serialize(std::ostream_iterator<char>(os));
return os;
}
@@ -885,235 +1190,3 @@ inline std::ostream& operator<<(std::ostream& os, const picojson::value& x) {
#endif
#endif
-#ifdef TEST_PICOJSON
-#ifdef _MSC_VER
-#pragma warning(disable : 4127) // conditional expression is constant
-#endif
-
-using namespace std;
-
-static void plan(int num) {
- printf("1..%d\n", num);
-}
-
-static bool success = true;
-
-static void ok(bool b, const char* name = "") {
- static int n = 1;
- if (!b) success = false;
- printf("%s %d - %s\n", b ? "ok" : "ng", n++, name);
-}
-
-template <typename T>
-void is(const T& x, const T& y, const char* name = "") {
- if (x == y) {
- ok(true, name);
- } else {
- ok(false, name);
- }
-}
-
-#include <float.h>
-#include <limits.h>
-#include <algorithm>
-#include <sstream>
-
-int main(void) {
- plan(85);
-
-// constructors
-#define TEST(expr, expected) \
- is(picojson::value expr.serialize(), string(expected), "picojson::value" #expr)
-
- TEST((true), "true");
- TEST((false), "false");
- TEST((42.0), "42");
- TEST((string("hello")), "\"hello\"");
- TEST(("hello"), "\"hello\"");
- TEST(("hello", 4), "\"hell\"");
-
- {
- double a = 1;
- for (int i = 0; i < 1024; i++) {
- picojson::value vi(a);
- std::stringstream ss;
- ss << vi;
- picojson::value vo;
- ss >> vo;
- double b = vo.get<double>();
- if ((i < 53 && a != b) || fabs(a - b) / b > 1e-8) {
- printf("ng i=%d a=%.18e b=%.18e\n", i, a, b);
- }
- a *= 2;
- }
- }
-
-#undef TEST
-
-#define TEST(in, type, cmp, serialize_test) \
- { \
- picojson::value v; \
- const char* s = in; \
- string err = picojson::parse(v, s, s + strlen(s)); \
- ok(err.empty(), in " no error"); \
- ok(v.is<type>(), in " check type"); \
- is<type>(v.get<type>(), cmp, in " correct output"); \
- is(*s, '\0', in " read to eof"); \
- if (serialize_test) { \
- is(v.serialize(), string(in), in " serialize"); \
- } \
- }
- TEST("false", bool, false, true);
- TEST("true", bool, true, true);
- TEST("90.5", double, 90.5, false);
- TEST("1.7976931348623157e+308", double, DBL_MAX, false);
- TEST("\"hello\"", string, string("hello"), true);
- TEST("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", string, string("\"\\/\b\f\n\r\t"), true);
- TEST("\"\\u0061\\u30af\\u30ea\\u30b9\"", string, string("a\xe3\x82\xaf\xe3\x83\xaa\xe3\x82\xb9"),
- false);
- TEST("\"\\ud840\\udc0b\"", string, string("\xf0\xa0\x80\x8b"), false);
-#undef TEST
-
-#define TEST(type, expr) \
- { \
- picojson::value v; \
- const char* s = expr; \
- string err = picojson::parse(v, s, s + strlen(s)); \
- ok(err.empty(), "empty " #type " no error"); \
- ok(v.is<picojson::type>(), "empty " #type " check type"); \
- ok(v.get<picojson::type>().empty(), "check " #type " array size"); \
- }
- TEST(array, "[]");
- TEST(object, "{}");
-#undef TEST
-
- {
- picojson::value v;
- const char* s = "[1,true,\"hello\"]";
- string err = picojson::parse(v, s, s + strlen(s));
- ok(err.empty(), "array no error");
- ok(v.is<picojson::array>(), "array check type");
- is(v.get<picojson::array>().size(), size_t(3), "check array size");
- ok(v.contains(0), "check contains array[0]");
- ok(v.get(0).is<double>(), "check array[0] type");
- is(v.get(0).get<double>(), 1.0, "check array[0] value");
- ok(v.contains(1), "check contains array[1]");
- ok(v.get(1).is<bool>(), "check array[1] type");
- ok(v.get(1).get<bool>(), "check array[1] value");
- ok(v.contains(2), "check contains array[2]");
- ok(v.get(2).is<string>(), "check array[2] type");
- is(v.get(2).get<string>(), string("hello"), "check array[2] value");
- ok(!v.contains(3), "check not contains array[3]");
- }
-
- {
- picojson::value v;
- const char* s = "{ \"a\": true }";
- string err = picojson::parse(v, s, s + strlen(s));
- ok(err.empty(), "object no error");
- ok(v.is<picojson::object>(), "object check type");
- is(v.get<picojson::object>().size(), size_t(1), "check object size");
- ok(v.contains("a"), "check contains property");
- ok(v.get("a").is<bool>(), "check bool property exists");
- is(v.get("a").get<bool>(), true, "check bool property value");
- is(v.serialize(), string("{\"a\":true}"), "serialize object");
- ok(!v.contains("z"), "check not contains property");
- }
-
-#define TEST(json, msg) \
- do { \
- picojson::value v; \
- const char* s = json; \
- string err = picojson::parse(v, s, s + strlen(s)); \
- is(err, string("syntax error at line " msg), msg); \
- } while (0)
- TEST("falsoa", "1 near: oa");
- TEST("{]", "1 near: ]");
- TEST("\n\bbell", "2 near: bell");
- TEST("\"abc\nd\"", "1 near: ");
-#undef TEST
-
- {
- picojson::value v1, v2;
- const char* s;
- string err;
- s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
- err = picojson::parse(v1, s, s + strlen(s));
- s = "{ \"d\": 2.0, \"b\": true, \"a\": [1,2,\"three\"] }";
- err = picojson::parse(v2, s, s + strlen(s));
- ok((v1 == v2), "check == operator in deep comparison");
- }
-
- {
- picojson::value v1, v2;
- const char* s;
- string err;
- s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
- err = picojson::parse(v1, s, s + strlen(s));
- s = "{ \"d\": 2.0, \"a\": [1,\"three\"], \"b\": true }";
- err = picojson::parse(v2, s, s + strlen(s));
- ok((v1 != v2), "check != operator for array in deep comparison");
- }
-
- {
- picojson::value v1, v2;
- const char* s;
- string err;
- s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
- err = picojson::parse(v1, s, s + strlen(s));
- s = "{ \"d\": 2.0, \"a\": [1,2,\"three\"], \"b\": false }";
- err = picojson::parse(v2, s, s + strlen(s));
- ok((v1 != v2), "check != operator for object in deep comparison");
- }
-
- {
- picojson::value v1, v2;
- const char* s;
- string err;
- s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
- err = picojson::parse(v1, s, s + strlen(s));
- picojson::object& o = v1.get<picojson::object>();
- o.erase("b");
- picojson::array& a = o["a"].get<picojson::array>();
- picojson::array::iterator i;
- i = std::remove(a.begin(), a.end(), picojson::value(std::string("three")));
- a.erase(i, a.end());
- s = "{ \"a\": [1,2], \"d\": 2 }";
- err = picojson::parse(v2, s, s + strlen(s));
- ok((v1 == v2), "check erase()");
- }
-
- ok(picojson::value(3.0).serialize() == "3", "integral number should be serialized as a integer");
-
- {
- const char* s = "{ \"a\": [1,2], \"d\": 2 }";
- picojson::null_parse_context ctx;
- string err;
- picojson::_parse(ctx, s, s + strlen(s), &err);
- ok(err.empty(), "null_parse_context");
- }
-
- {
- picojson::value v1, v2;
- v1 = picojson::value(true);
- swap(v1, v2);
- ok(v1.is<picojson::null>(), "swap (null)");
- ok(v2.get<bool>() == true, "swap (bool)");
-
- v1 = picojson::value("a");
- v2 = picojson::value(1.0);
- swap(v1, v2);
- ok(v1.get<double>() == 1.0, "swap (dobule)");
- ok(v2.get<string>() == "a", "swap (string)");
-
- v1 = picojson::value(picojson::object());
- v2 = picojson::value(picojson::array());
- swap(v1, v2);
- ok(v1.is<picojson::array>(), "swap (array)");
- ok(v2.is<picojson::object>(), "swap (object)");
- }
-
- return success ? 0 : 1;
-}
-
-#endif
diff --git a/src/common/platform_enum.h b/src/common/platform_enum.h
new file mode 100644
index 00000000..6c626954
--- /dev/null
+++ b/src/common/platform_enum.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMMON_PLATFORM_ENUM_H_
+#define COMMON_PLATFORM_ENUM_H_
+
+#include "platform_result.h"
+
+#include <string>
+#include <map>
+#include <vector>
+#include <initializer_list>
+
+
+namespace common {
+
+
+template<typename NativeEnumType>
+class PlatformEnum
+{
+using MapType = std::map<std::string, NativeEnumType>;
+using RevMapType = std::map<NativeEnumType, std::string>;
+
+using MapTypeConstIter = typename MapType::const_iterator;
+
+public:
+ PlatformEnum(std::initializer_list<std::pair<const std::string, NativeEnumType>> m) : mapping_(m) {
+ for (auto it: mapping_) {
+ rev_mapping_[it.second] = it.first;
+ }
+ }
+
+ PlatformResult getName(NativeEnumType value, std::string* name) const {
+ auto it = rev_mapping_.find(value);
+ if (it != rev_mapping_.end()) {
+ *name = it->second;
+ return PlatformResult(ErrorCode::NO_ERROR);
+ }
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "enum value not registered");
+ }
+
+ PlatformResult getValue(std::string name, NativeEnumType* value) const {
+ auto it = mapping_.find(name);
+ if (it != mapping_.end()) {
+ *value = it->second;
+ return PlatformResult(ErrorCode::NO_ERROR);
+ }
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "enum name not registered");
+ }
+
+ MapTypeConstIter begin() const {
+ return mapping_.cbegin();
+ }
+
+ MapTypeConstIter end() const {
+ return mapping_.cend();
+ }
+
+private:
+ MapType mapping_;
+ RevMapType rev_mapping_;
+};
+
+
+} // common
+
+
+#endif // COMMON_PLATFORM_ENUM_H_
diff --git a/src/common/task-queue.cpp b/src/common/task-queue.cpp
index 9bafdae4..fe551a5e 100644
--- a/src/common/task-queue.cpp
+++ b/src/common/task-queue.cpp
@@ -24,44 +24,54 @@ TaskQueue& TaskQueue::GetInstance() {
}
template <>
-gboolean TaskQueue::AfterWorkCallback<void>(gpointer data) {
+gboolean TaskQueue::WorkCallback<void>(gpointer data) {
QueueData<void>* d = static_cast<QueueData<void>*>(data);
if (nullptr != d) {
- d->after_work_callback_();
+ d->work_callback_();
delete d;
}
return FALSE;
}
-template <>
-void* TaskQueue::WorkCallback<void>(void* data) {
- QueueData<void>* d = static_cast<QueueData<void>*>(data);
- if (nullptr != d) {
- d->work_callback_();
- if (d->after_work_callback_) {
- g_idle_add(AfterWorkCallback<void>, d);
- }
- }
- return nullptr;
+void TaskQueue::Queue(const std::function<void()>& work, const std::function<void()>& after_work) {
+ auto do_work = [work, after_work]() {
+ work();
+ after_work();
+ };
+ this->queue_worker_.add_job(do_work);
}
-void TaskQueue::Queue(const std::function<void()>& work, const std::function<void()>& after_work) {
- QueueData<void>* d = new QueueData<void>();
- d->work_callback_ = work;
- d->after_work_callback_ = after_work;
+void TaskQueue::Async(const std::function<void()>& work) {
+ this->async_worker_.add_job(work);
+}
- if (pthread_create(&d->thread_, nullptr, WorkCallback<void>, d) != 0) {
- LoggerE("Failed to create a background thread.");
- delete d;
- } else {
- pthread_detach(d->thread_);
+void TaskQueue::Async(const std::function<void(const common::AsyncToken& token)>& work,
+ const common::AsyncToken& token) {
+ auto do_work = [work, token]() { work(token); };
+ Async(do_work);
+}
+
+void TaskQueue::DeleteJobs() {
+ {
+ std::lock_guard<std::mutex> lck{this->queue_worker_.jobs_mtx};
+ this->queue_worker_.jobs.clear();
+ }
+ {
+ std::lock_guard<std::mutex> lck{this->async_worker_.jobs_mtx};
+ this->async_worker_.jobs.clear();
}
}
-void TaskQueue::Async(const std::function<void()>& work) {
+void TaskQueue::Stop() {
+ LoggerI("Stopping TaskQueue workers");
+ queue_worker_.stop();
+ async_worker_.stop();
+}
+
+void TaskQueue::ScheduleWorkInMainThread(const std::function<void()>& work) {
QueueData<void>* d = new QueueData<void>();
- d->after_work_callback_ = work;
- g_idle_add(AfterWorkCallback<void>, d);
+ d->work_callback_ = work;
+ g_idle_add(WorkCallback<void>, d);
}
} // namespace common
diff --git a/src/common/task-queue.h b/src/common/task-queue.h
index fb3300a3..c44cc09c 100644
--- a/src/common/task-queue.h
+++ b/src/common/task-queue.h
@@ -22,23 +22,55 @@
#include <functional>
#include <memory>
-#include "logger.h"
+#include "tizen_instance.h"
+#include "worker.h"
namespace common {
+/**
+ * TaskQueue is a class, which aggregates two instances of Worker class.
+ * The class contains two workers to prevent from blocking jobs, which should execute and return
+ * results after a few seconds.
+ */
class TaskQueue {
- public:
- TaskQueue(const TaskQueue&) = delete;
- TaskQueue& operator=(const TaskQueue&) = delete;
+ private:
+ TaskQueue() {
+ }
+ /**
+ * Worker for asynchronous 'quick' jobs.
+ * This queue is supposed to hold jobs, which are expected to take 'a little' time.
+ */
+ Worker async_worker_;
+ /**
+ * Worker for asynchronous 'long' jobs.
+ * This queue is supposed to hold jobs, which are expected to take 'long' time.
+ */
+ Worker queue_worker_;
+
+ public:
static TaskQueue& GetInstance();
+ ~TaskQueue() {
+ }
+
+ /**
+ * Method used to clear all delegated jobs during lifetime of UtilsInstance class.
+ * The UtilsInstance class is the first constructed and the last destructed instance of Instance
+ * class, which determines the lifetime of frame in the page.
+ */
+ void DeleteJobs();
+
+ /**
+ * Stops the workers. This method should be called only once, before shutting down the process.
+ * After that time, no more messages will be sent to Crosswalk.
+ */
+ void Stop();
/**
- * @brief Schedules work to be executed in a separate thread, after_work is going
- * to be called in main glib loop.
+ * @brief Schedule a 'long' job
*
- * @param[in] work - callback is going to be called in a separate thread
- * @param[in] after_work - callback is going to be called in main glib loop
+ * @param[in] work - callback is going to be called in a worker's thread
+ * @param[in] after_work - callback is going to be called after work
* @param[in] data - data passed to both callbacks
*/
template <class T>
@@ -47,19 +79,17 @@ class TaskQueue {
const std::shared_ptr<T>& data);
/**
- * @brief Schedules work to be executed in a separate thread, after_work is going
- * to be called in main glib loop.
+ * @brief Schedule a 'long' job
*
- * @param[in] work - callback is going to be called in a separate thread
- * @param[in] after_work - callback is going to be called in main glib loop
+ * @param[in] work - callback is going to be called in a worker's thread
+ * @param[in] after_work - callback is going to be called after work function
*/
- void Queue(const std::function<void()>& work,
- const std::function<void()>& after_work = std::function<void()>());
+ void Queue(const std::function<void()>& work, const std::function<void()>& after_work = [] {});
/**
- * @brief Schedules work to be executed in main glib loop.
+ * @brief Schedule a 'quick' job
*
- * @param[in] work - callback is going to be called in main glib loop
+ * @param[in] work - callback is going to be called in a worker's thread
* @param[in] data - data passed to callback
*/
template <class T>
@@ -67,82 +97,98 @@ class TaskQueue {
const std::shared_ptr<T>& data);
/**
- * @brief Schedules work to be executed in main glib loop.
+ * @brief Schedule a 'quick' job
*
- * @param[in] work - callback is going to be called in main glib loop
+ * @param[in] work - callback is going to be called in a worker's thread
*/
void Async(const std::function<void()>& work);
- private:
- TaskQueue() {
- }
+ /**
+ * @brief Schedule a 'quick' job requiring AsyncToken
+ *
+ * @param[in] work - callback is going to be called in a worker's thread
+ * @param[in] token - token passed to the work function
+ */
+ void Async(const std::function<void(const common::AsyncToken& token)>& work,
+ const common::AsyncToken& token);
+
+ /**
+ * @brief Schedules work to be executed in main glib loop
+ *
+ * This method should be used only for jobs, which HAVE to be executed in main loop of the
+ * process.
+ *
+ * @param[in] work - callback is going to be called in main glib loop
+ * @param[in] data - data passed to callback
+ */
+ template <class T>
+ void ScheduleWorkInMainThread(const std::function<void(const std::shared_ptr<T>&)>& work,
+ const std::shared_ptr<T>& data);
+ /**
+ * @brief Schedules work to be executed in main glib loop
+ *
+ * This method should be used only for jobs, which HAVE to be executed in main loop of the
+ * process.
+ *
+ * @param[in] work - callback is going to be called in main glib loop
+ */
+ void ScheduleWorkInMainThread(const std::function<void()>& work);
template <class T>
struct QueueData {
- pthread_t thread_;
std::function<void(const std::shared_ptr<T>&)> work_callback_;
- std::function<void(const std::shared_ptr<T>&)> after_work_callback_;
std::shared_ptr<T> data_;
};
template <class T>
- static void* WorkCallback(void* data);
+ static gboolean WorkCallback(gpointer data);
- template <class T>
- static gboolean AfterWorkCallback(gpointer data);
+ TaskQueue(const TaskQueue&) = delete;
+ TaskQueue& operator=(const TaskQueue&) = delete;
+ TaskQueue(TaskQueue&&) = delete;
+ TaskQueue& operator=(TaskQueue&&) = delete;
};
template <>
struct TaskQueue::QueueData<void> {
- pthread_t thread_;
std::function<void()> work_callback_;
- std::function<void()> after_work_callback_;
};
template <class T>
-gboolean TaskQueue::AfterWorkCallback(gpointer data) {
+gboolean TaskQueue::WorkCallback(gpointer data) {
QueueData<T>* d = static_cast<QueueData<T>*>(data);
if (nullptr != d) {
- d->after_work_callback_(d->data_);
+ d->work_callback_(d->data_);
delete d;
}
return FALSE;
}
template <class T>
-void* TaskQueue::WorkCallback(void* data) {
- QueueData<T>* d = static_cast<QueueData<T>*>(data);
- if (nullptr != d) {
- d->work_callback_(d->data_);
- g_idle_add(AfterWorkCallback<T>, d);
- }
- return nullptr;
-}
-
-template <class T>
void TaskQueue::Queue(const std::function<void(const std::shared_ptr<T>&)>& work,
const std::function<void(const std::shared_ptr<T>&)>& after_work,
const std::shared_ptr<T>& data) {
- QueueData<T>* d = new QueueData<T>();
- d->work_callback_ = work;
- d->after_work_callback_ = after_work;
- d->data_ = data;
-
- if (pthread_create(&d->thread_, nullptr, WorkCallback<T>, d) != 0) {
- LoggerE("Failed to create a background thread.");
- delete d;
- } else {
- pthread_detach(d->thread_);
- }
+ auto do_work = [data, work, after_work]() {
+ work(data);
+ after_work(data);
+ };
+ this->queue_worker_.add_job(do_work);
}
template <class T>
void TaskQueue::Async(const std::function<void(const std::shared_ptr<T>&)>& work,
const std::shared_ptr<T>& data) {
+ auto do_work = [data, work]() { work(data); };
+ this->async_worker_.add_job(do_work);
+}
+
+template <class T>
+void TaskQueue::ScheduleWorkInMainThread(const std::function<void(const std::shared_ptr<T>&)>& work,
+ const std::shared_ptr<T>& data) {
QueueData<T>* d = new QueueData<T>();
- d->after_work_callback_ = work;
+ d->work_callback_ = work;
d->data_ = data;
- g_idle_add(AfterWorkCallback<T>, d);
+ g_idle_add(WorkCallback<T>, d);
}
} // namespace common
diff --git a/src/common/tools.cc b/src/common/tools.cc
index c1d49984..fd4a2f30 100644
--- a/src/common/tools.cc
+++ b/src/common/tools.cc
@@ -446,6 +446,23 @@ bool IsAppVersionEarlierThan(const std::string& ver) {
return false;
}
+/*
+ * RequestStoragePrivilegeChecker structure is used to check whether the file stating is needed.
+ * File stating is done to ensure that the application has given access to files on
+ * internal/external memory. The checking is done since Tizen 5.0 for applications, which
+ * require at least 5.0 version of Tizen.
+ * */
+struct RequestStoragePrivilegeChecker {
+ bool isStorageAccessCheckNeeded;
+ RequestStoragePrivilegeChecker() : isStorageAccessCheckNeeded(!IsAppVersionEarlierThan("5.0")) {
+ }
+};
+
+bool IsStoragePrivilegeCheckNeeded() {
+ static RequestStoragePrivilegeChecker checker{};
+ return checker.isStorageAccessCheckNeeded;
+}
+
std::string GetErrorString(int error_code) {
static const size_t kSize = 1024;
char msg[kSize] = {0};
@@ -491,6 +508,37 @@ bool IsPathValid(const std::string& path) {
path.length() - 3 != path.rfind("/..");
}
+PlatformResult CheckStorageAccess(const std::string& path) {
+ ScopeLogger("path: [%s]", path.c_str());
+ struct stat buf {};
+ char* real_path = realpath(path.c_str(), nullptr);
+ SCOPE_EXIT {
+ free(real_path);
+ };
+ if ((nullptr == real_path || -1 == stat(real_path, &buf)) && (EACCES == errno)) {
+ LoggerE("The application does not have necessary privilege to access given file: [%s]",
+ path.c_str());
+ return PlatformResult(ErrorCode::SECURITY_ERR,
+ "Permission denied: accessing files requires proper storage privilege");
+ }
+ return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+TizenResult CheckStorageAccessAndReturn(const std::string& path) {
+ ScopeLogger("path: [%s]", path.c_str());
+ struct stat buf {};
+ char* real_path = realpath(path.c_str(), nullptr);
+ SCOPE_EXIT {
+ free(real_path);
+ };
+ if ((nullptr == real_path || -1 == stat(real_path, &buf)) && (EACCES == errno)) {
+ LoggerE("The application does not have necessary privilege to access given file: [%s]",
+ path.c_str());
+ return SecurityError("Permission denied: accessing files requires proper storage privilege");
+ }
+ return TizenSuccess();
+}
+
PlatformResult CheckFileStatus(const std::string& path) {
ScopeLogger();
diff --git a/src/common/tools.h b/src/common/tools.h
index d72a09b8..88136c48 100644
--- a/src/common/tools.h
+++ b/src/common/tools.h
@@ -23,6 +23,7 @@
#include "common/picojson.h"
#include "common/platform_exception.h"
#include "common/platform_result.h"
+#include "common/tizen_result.h"
namespace common {
namespace tools {
@@ -35,8 +36,10 @@ void ReportError(const PlatformResult& error, picojson::object* out);
common::PlatformResult CheckAccess(const std::string& privilege);
common::PlatformResult CheckAccess(const std::vector<std::string>& privileges);
+common::PlatformResult CheckStorageAccess(const std::string& path);
+common::TizenResult CheckStorageAccessAndReturn(const std::string& path);
common::PlatformResult GetPkgApiVersion(std::string* api_version);
-
+bool IsStoragePrivilegeCheckNeeded();
bool IsAppVersionEarlierThan(const std::string& ver);
// it is used for modules which return TizenResult objects to JS layer
@@ -57,6 +60,29 @@ bool IsAppVersionEarlierThan(const std::string& ver);
} \
} while (0)
+// The below macro is designed to check, whether the application has necessary privilege in order
+// to access resource on internal or external memory.
+#define CHECK_STORAGE_ACCESS(path, out) \
+ do { \
+ if (common::tools::IsStoragePrivilegeCheckNeeded()) { \
+ auto ret = common::tools::CheckStorageAccess(path); \
+ if (!ret) { \
+ common::tools::ReportError(ret, out); \
+ return; \
+ } \
+ } \
+ } while (0)
+
+#define CHECK_STORAGE_ACCESS_AND_RETURN(path) \
+ do { \
+ if (common::tools::IsStoragePrivilegeCheckNeeded()) { \
+ auto ret = common::tools::CheckStorageAccessAndReturn(path); \
+ if (!ret) { \
+ return ret; \
+ } \
+ } \
+ } while (0)
+
#define CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(current_priv, prev_priv, out) \
do { \
auto ret = common::tools::CheckAccess(current_priv); \
diff --git a/src/common/worker.cc b/src/common/worker.cc
new file mode 100644
index 00000000..4442c992
--- /dev/null
+++ b/src/common/worker.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "worker.h"
+
+namespace common {
+
+void Worker::main() {
+ std::unique_lock<std::mutex> lck{jobs_mtx};
+ while (true) {
+ jobs_cond.wait(lck, [this] { return !jobs.empty() || exit; });
+ if (exit) {
+ return;
+ }
+
+ while (!jobs.empty()) {
+ auto job = jobs.front();
+ jobs.pop_front();
+ //////////// end of critical section
+ lck.unlock();
+
+ try {
+ job.func();
+ } catch (...) {
+ // should never happen
+ LoggerE("Func should never throw");
+ }
+
+ try {
+ job.finally();
+ } catch (...) {
+ // should never happen
+ LoggerE("Finally should never throw");
+ }
+
+ lck.lock();
+ //////////// start of critical section
+ if (exit) {
+ return;
+ }
+ }
+ }
+}
+
+void Worker::add_job(const std::function<void()>& func, const std::function<void()>& finally) {
+ {
+ std::lock_guard<std::mutex> lck{jobs_mtx};
+ jobs.push_back({func, finally});
+ }
+ jobs_cond.notify_one();
+}
+
+Worker::Worker() : exit(false), thread(std::bind(&Worker::main, this)) {
+}
+
+Worker::~Worker() {
+ if (!exit && thread.joinable()) {
+ stop();
+ }
+}
+
+void Worker::stop() {
+ {
+ // use memory barrier for exit flag (could be std::atomic_flag, but we use lock instead)
+ std::lock_guard<std::mutex> lck{jobs_mtx};
+ exit = true;
+ }
+ jobs_cond.notify_one();
+
+ try {
+ thread.join();
+ } catch (std::exception& e) {
+ LoggerE("Failed to join thread: %s", e.what());
+ }
+
+ // finalize jobs left in queue
+ for (auto job : jobs) {
+ try {
+ job.finally();
+ } catch (...) {
+ // should never happen
+ LoggerE("Finally should never throw");
+ }
+ }
+}
+
+} // namespace common \ No newline at end of file
diff --git a/src/common/worker.h b/src/common/worker.h
new file mode 100644
index 00000000..85aea8b9
--- /dev/null
+++ b/src/common/worker.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WEBAPI_PLUGINS_COMMON_WORKER_H_
+#define WEBAPI_PLUGINS_COMMON_WORKER_H_
+
+#include <condition_variable>
+#include <deque>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include "common/logger.h"
+
+namespace common {
+
+/**
+ * @brief Implements single worker executing in new thread
+ *
+ * Jobs are done in FIFO order. If this worker is destroyed all pending jobs are cancelled,
+ * and all remaining 'finally' functions are called.
+ */
+class Worker {
+ private:
+ friend class TaskQueue;
+ bool exit;
+ struct Job {
+ std::function<void()> func;
+ std::function<void()> finally;
+ };
+ std::mutex jobs_mtx;
+ std::condition_variable jobs_cond;
+ std::deque<Job> jobs;
+ std::thread thread;
+ void main(void);
+
+ public:
+ Worker();
+ virtual ~Worker();
+ void stop();
+
+ /**
+ * @brief Schedule a job
+ * Parameters will be copied (no reference is held)
+ *
+ * @param job function called as a job (should not throw)
+ * @param finally function called after completion or canceling. (should not throw)
+ */
+ virtual void add_job(const std::function<void()>& job, const std::function<void()>& finally);
+
+ /**
+ * @brief Schedule a job. Same as above, but with empty finally function.
+ * Parameter will be copied (no reference is held)
+ *
+ * @param job function called as a job (should not throw)
+ */
+ virtual void add_job(const std::function<void()>& job) {
+ add_job(job, [] {});
+ }
+
+ Worker(const Worker&) = delete;
+ Worker& operator=(const Worker&) = delete;
+};
+
+} // namespace common
+
+#endif // WEBAPI_PLUGINS_COMMON_WORKER_H_ \ No newline at end of file
diff --git a/src/contact/contact_instance.cc b/src/contact/contact_instance.cc
index 0b58bd8e..939aaf07 100644
--- a/src/contact/contact_instance.cc
+++ b/src/contact/contact_instance.cc
@@ -17,6 +17,7 @@
#include "contact/contact_instance.h"
#include "common/converter.h"
+#include "common/filesystem/filesystem_provider.h"
#include "common/logger.h"
#include "common/platform_exception.h"
#include "common/task-queue.h"
@@ -32,7 +33,31 @@ namespace contact {
namespace {
const std::string kPrivilegeContactRead = "http://tizen.org/privilege/contact.read";
const std::string kPrivilegeContactWrite = "http://tizen.org/privilege/contact.write";
-}
+const std::vector<const char*> kContactURIs = {"photoURI", "ringtoneURI", "vibrationURI",
+ "messageAlertURI"};
+const std::vector<const char*> kPersonGroupURIs = {"photoURI", "ringtoneURI"};
+const std::vector<const char*> kOrganizationURIs = {"logoURI"};
+}
+
+#define CHECK_CONTACT_ATTRIBUTES_STORAGE(in, to_check, out) \
+ do { \
+ for (auto& attr : to_check) { \
+ if (!IsNull(in, attr)) { \
+ const std::string& real_path = \
+ common::FilesystemProvider::Create().GetRealPath(FromJson<std::string>(in, attr)); \
+ CHECK_STORAGE_ACCESS(real_path, out); \
+ } \
+ } \
+ } while (0);
+
+#define CHECK_CONTACT_ATTRIBUTES_ARRAY(in, attribute, to_check, out) \
+ do { \
+ JsonArray array = FromJson<JsonArray>(in, attribute); \
+ for (auto& el : array) { \
+ JsonObject element = common::JsonCast<JsonObject>(el); \
+ CHECK_CONTACT_ATTRIBUTES_STORAGE(element, to_check, out); \
+ } \
+ } while (0);
using namespace common;
@@ -110,6 +135,11 @@ void ContactInstance::AddressBookGet(const JsonValue& args, JsonObject& out) {
void ContactInstance::AddressBookAdd(const JsonValue& args, JsonObject& out) {
ScopeLogger();
CHECK_PRIVILEGE_ACCESS(kPrivilegeContactWrite, &out);
+
+ const auto& contact = args.get("contact").get<JsonObject>();
+ CHECK_CONTACT_ATTRIBUTES_STORAGE(contact, kContactURIs, &out);
+ CHECK_CONTACT_ATTRIBUTES_ARRAY(contact, "organizations", kOrganizationURIs, &out);
+
JsonValue val{JsonObject{}};
PlatformResult status =
AddressBook::AddressBookAdd(common::JsonCast<JsonObject>(args), val.get<JsonObject>());
@@ -123,6 +153,13 @@ void ContactInstance::AddressBookAddBatch(const JsonValue& args, JsonObject& out
ScopeLogger();
CHECK_PRIVILEGE_ACCESS(kPrivilegeContactWrite, &out);
+ const auto& batch_args = args.get("batchArgs").get<JsonArray>();
+ for (auto& item : batch_args) {
+ JsonObject contact = common::JsonCast<JsonObject>(item);
+ CHECK_CONTACT_ATTRIBUTES_STORAGE(contact, kContactURIs, &out);
+ CHECK_CONTACT_ATTRIBUTES_ARRAY(contact, "organizations", kOrganizationURIs, &out);
+ }
+
const double callback_id = args.get("callbackId").get<double>();
auto get = [=](const std::shared_ptr<JsonValue>& response) -> void {
@@ -180,6 +217,13 @@ void ContactInstance::AddressBookUpdateBatch(const JsonValue& args, JsonObject&
ScopeLogger();
CHECK_PRIVILEGE_ACCESS(kPrivilegeContactWrite, &out);
+ const auto& batch_args = args.get("batchArgs").get<JsonArray>();
+ for (auto& item : batch_args) {
+ JsonObject contact = common::JsonCast<JsonObject>(item);
+ CHECK_CONTACT_ATTRIBUTES_STORAGE(contact, kContactURIs, &out);
+ CHECK_CONTACT_ATTRIBUTES_ARRAY(contact, "organizations", kOrganizationURIs, &out);
+ }
+
const double callback_id = args.get("callbackId").get<double>();
auto get = [=](const std::shared_ptr<JsonValue>& response) -> void {
@@ -208,6 +252,11 @@ void ContactInstance::AddressBookUpdateBatch(const JsonValue& args, JsonObject&
void ContactInstance::AddressBookUpdate(const JsonValue& args, JsonObject& out) {
ScopeLogger();
CHECK_PRIVILEGE_ACCESS(kPrivilegeContactWrite, &out);
+
+ const auto& contact = args.get("contact").get<JsonObject>();
+ CHECK_CONTACT_ATTRIBUTES_STORAGE(contact, kContactURIs, &out);
+ CHECK_CONTACT_ATTRIBUTES_ARRAY(contact, "organizations", kOrganizationURIs, &out);
+
JsonValue val{JsonObject{}};
PlatformResult status =
AddressBook::AddressBookUpdate(common::JsonCast<JsonObject>(args), val.get<JsonObject>());
@@ -260,6 +309,10 @@ void ContactInstance::AddressBookFind(const JsonValue& args, JsonObject& out) {
void ContactInstance::AddressBookAddGroup(const JsonValue& args, JsonObject& out) {
ScopeLogger();
CHECK_PRIVILEGE_ACCESS(kPrivilegeContactWrite, &out);
+
+ const auto& group = args.get("group").get<JsonObject>();
+ CHECK_CONTACT_ATTRIBUTES_STORAGE(group, kPersonGroupURIs, &out);
+
JsonValue val{JsonObject{}};
PlatformResult status =
AddressBook::AddressBookAddGroup(common::JsonCast<JsonObject>(args), val.get<JsonObject>());
@@ -283,6 +336,10 @@ void ContactInstance::AddressBookGetGroup(const JsonValue& args, JsonObject& out
void ContactInstance::AddressBookUpdateGroup(const JsonValue& args, JsonObject& out) {
ScopeLogger();
+
+ const auto& group = args.get("group").get<JsonObject>();
+ CHECK_CONTACT_ATTRIBUTES_STORAGE(group, kPersonGroupURIs, &out);
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeContactWrite, &out);
JsonValue val{JsonObject{}};
PlatformResult status = AddressBook::AddressBookUpdateGroup(common::JsonCast<JsonObject>(args),
@@ -421,6 +478,10 @@ void ContactInstance::ContactManagerGet(const JsonValue& args, JsonObject& out)
void ContactInstance::ContactManagerUpdate(const JsonValue& args, JsonObject& out) {
ScopeLogger();
CHECK_PRIVILEGE_ACCESS(kPrivilegeContactWrite, &out);
+
+ const auto& group = args.get("person").get<JsonObject>();
+ CHECK_CONTACT_ATTRIBUTES_STORAGE(group, kPersonGroupURIs, &out);
+
JsonValue val{JsonObject{}};
PlatformResult status = ContactManager::ContactManagerUpdate(common::JsonCast<JsonObject>(args),
val.get<JsonObject>());
@@ -434,6 +495,12 @@ void ContactInstance::ContactManagerUpdateBatch(const JsonValue& args, JsonObjec
ScopeLogger();
CHECK_PRIVILEGE_ACCESS(kPrivilegeContactWrite, &out);
+ const auto& batch_args = args.get("batchArgs").get<JsonArray>();
+ for (auto& item : batch_args) {
+ JsonObject contact = common::JsonCast<JsonObject>(item);
+ CHECK_CONTACT_ATTRIBUTES_STORAGE(contact, kPersonGroupURIs, &out);
+ }
+
const double callback_id = args.get("callbackId").get<double>();
auto get = [=](const std::shared_ptr<JsonValue>& response) -> void {
@@ -640,6 +707,8 @@ void ContactInstance::PersonResetUsageCount(const JsonValue& args, JsonObject& o
} else {
LogAndReportError(status, &out);
}
+#undef CHECK_CONTACT_ATTRIBUTES_STORAGE
+#undef CHECK_CONTACT_ATTRIBUTES_ARRAY
}
} // namespace contact
diff --git a/src/contact/contact_util.cc b/src/contact/contact_util.cc
index eeefc421..f1078433 100644
--- a/src/contact/contact_util.cc
+++ b/src/contact/contact_util.cc
@@ -1731,7 +1731,7 @@ PlatformResult ImportContactInstantMessengerFromContactsRecord(contacts_record_h
int err = contacts_record_get_child_record_at_p(contacts_record, _contacts_contact.messenger,
index, &child_record);
if (CONTACTS_ERROR_NONE != err && CONTACTS_ERROR_NO_DATA != err) {
- LoggerW("Skipping message with index %i. error code: %i", index, err);
+ LoggerW("Skipping message with index %u. error code: %i", index, err);
return PlatformResult(ErrorCode::NO_ERROR);
}
@@ -1744,7 +1744,7 @@ PlatformResult ImportContactInstantMessengerFromContactsRecord(contacts_record_h
}
if (!im_address) {
- LoggerW("Skipping message with index %i. missing im address", index);
+ LoggerW("Skipping message with index %u. missing im address", index);
return PlatformResult(ErrorCode::NO_ERROR);
}
@@ -2201,7 +2201,7 @@ PlatformResult ImportGroupIdsFromContactsRecord(contacts_record_h contacts_recor
index, &record);
if (CONTACTS_ERROR_NONE != err && CONTACTS_ERROR_NO_DATA != err) {
// ignoring this record
- LoggerW("Skipping record with index %i. error code: %i", index, err);
+ LoggerW("Skipping record with index %u. error code: %i", index, err);
return PlatformResult(ErrorCode::NO_ERROR);
}
@@ -2914,18 +2914,6 @@ PlatformResult ExportPersonToContactsRecord(contacts_record_h record, const Json
return status;
}
- if (!IsNull(args, "photoURI") && !FromJson<JsonString>(args, "photoURI").empty()) {
- PlatformResult status = ContactUtil::SetStrInRecord(
- record, _contacts_person.image_thumbnail_path,
- ConvertUriToPath(FromJson<JsonString>(args, "photoURI")).c_str());
- if (status.IsError()) {
- LoggerE("Try updating read only attribute photoURI");
- return status;
- }
- } else {
- // TO DO: fix when photoURI attribute changed from read only to write mode
- }
-
if (!IsNull(args, "ringtoneURI")) {
PlatformResult status = ContactUtil::SetStrInRecord(
record, _contacts_person.ringtone_path,
diff --git a/src/contact/js/contact.js b/src/contact/js/contact.js
index cf5098a1..dcdd7def 100755
--- a/src/contact/js/contact.js
+++ b/src/contact/js/contact.js
@@ -32,8 +32,8 @@ var Contact = function(data) {
data.addressBookId = null;
data.lastUpdate = null;
- // Force edit mode so that anonymous objects can be promoted
- // to their correct types.
+ // Force edit mode so that anonymous objects can be promoted to their
+ // correct types.
_forceEditMode = true;
} else if (type_.isObject(data) || type_.isFunction(data)) {
// It's a dictionary
diff --git a/src/contact/js/person.js b/src/contact/js/person.js
index 16072c14..edcf84ba 100755
--- a/src/contact/js/person.js
+++ b/src/contact/js/person.js
@@ -118,7 +118,7 @@ var Person = function(data) {
},
photoURI: {
value: data.hasOwnProperty('photoURI') ? data.photoURI : null,
- writable: true,
+ writable: false,
enumerable: true
},
ringtoneURI: {
diff --git a/src/content/content_instance.cc b/src/content/content_instance.cc
index 8a3de66c..bc75361b 100644
--- a/src/content/content_instance.cc
+++ b/src/content/content_instance.cc
@@ -242,67 +242,11 @@ static void ScanDirectoryCallback(media_content_error_e error, void* user_data)
common::Instance::PostMessage(cbData->instance, picojson::value(out).serialize().c_str());
}
-// DEPRECATED CALLBACK. contentChangeCallback() is currently in use
-static void changedContentV1Callback(media_content_error_e error, int pid,
- media_content_db_update_item_type_e update_item,
- media_content_db_update_type_e update_type,
- media_content_type_e media_type, char* uuid, char* path,
- char* mime_type, void* user_data) {
- ScopeLogger("File change callback");
-
- if (error != MEDIA_CONTENT_ERROR_NONE) {
- LoggerE("Media content changed callback error: %d", (int)error);
- return;
- }
-
- if (update_item == MEDIA_ITEM_FILE) {
- if (!uuid) {
- LoggerE("Provided uuid is NULL, ignoring");
- return;
- }
-
- ReplyCallbackData* cbData = static_cast<ReplyCallbackData*>(user_data);
-
- int ret;
- picojson::value result = picojson::value(picojson::object());
- picojson::object& obj = result.get<picojson::object>();
-
- if (update_type == MEDIA_CONTENT_INSERT || update_type == MEDIA_CONTENT_UPDATE) {
- media_info_h media = NULL;
- ret = media_info_get_media_from_db(uuid, &media);
- if (ret == MEDIA_CONTENT_ERROR_NONE && media != NULL) {
- picojson::object o;
-
- ContentToJson(media, o);
- ReportSuccess(picojson::value(o), obj);
-
- if (update_type == MEDIA_CONTENT_INSERT) {
- obj["state"] = picojson::value("oncontentadded");
- } else {
- obj["state"] = picojson::value("oncontentupdated");
- }
-
- media_info_destroy(media);
- }
- } else {
- ReportSuccess(picojson::value(std::string(uuid)), obj);
- obj["state"] = picojson::value("oncontentremoved");
- }
-
- obj["listenerId"] = cbData->args.get("listenerId");
- common::Instance::PostMessage(cbData->instance, result.serialize().c_str());
- } else {
- LoggerD("Media item is not a file, skipping.");
- return;
- }
-}
-
-// DEPRECATED CALLBACK. contentChangeCallback() is currently in use
-static void changedContentV2Callback(media_content_error_e error, int pid,
- media_content_db_update_item_type_e update_item,
- media_content_db_update_type_e update_type,
- media_content_type_e media_type, char* uuid, char* path,
- char* mime_type, void* user_data) {
+static void changedContentCallback(media_content_error_e error, int pid,
+ media_content_db_update_item_type_e update_item,
+ media_content_db_update_type_e update_type,
+ media_content_type_e media_type, char* uuid, char* path,
+ char* mime_type, void* user_data) {
ScopeLogger("Directory change callback");
if (error != MEDIA_CONTENT_ERROR_NONE) {
@@ -566,6 +510,11 @@ void ContentInstance::ContentManagerScanfile(const picojson::value& args, picojs
CHECK_EXIST(args, "callbackId", out)
CHECK_EXIST(args, "contentURI", out)
+ const std::string& contentURI = args.get("contentURI").get<std::string>();
+ const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(contentURI);
+
+ CHECK_STORAGE_ACCESS(real_path, &out);
+
double callbackId = args.get("callbackId").get<double>();
auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
cbData->callbackId = callbackId;
@@ -588,6 +537,11 @@ void ContentInstance::ContentManagerScanDirectory(const picojson::value& args,
CHECK_EXIST(args, "contentDirURI", out)
CHECK_EXIST(args, "recursive", out)
+ const std::string& contentURI = args.get("contentDirURI").get<std::string>();
+ const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(contentURI);
+
+ CHECK_STORAGE_ACCESS(real_path, &out);
+
ReplyCallbackData* cbData = new ReplyCallbackData;
cbData->callbackId = args.get("callbackId").get<double>();
cbData->instance = this;
@@ -678,17 +632,9 @@ void ContentInstance::ContentManagerSetchangelistener(const picojson::value& arg
listener_data_->cbType = ContentManagerErrorCallback;
}
- if (ContentManager::getInstance()
- ->setChangeListener(changedContentV1Callback, static_cast<void*>(listener_data_))
- .IsError()) {
- LogAndReportError(common::PlatformResult(common::ErrorCode::UNKNOWN_ERR,
- "The callback did not register properly"),
- &out);
- }
-
if (nullptr == noti_handle_) { // To remain consistency with the previous implementation
if (ContentManager::getInstance()
- ->addChangeListener(&noti_handle_, changedContentV2Callback,
+ ->addChangeListener(&noti_handle_, changedContentCallback,
static_cast<void*>(listener_data_))
.IsError()) {
LogAndReportError(common::PlatformResult(common::ErrorCode::UNKNOWN_ERR,
@@ -708,9 +654,6 @@ void ContentInstance::ContentManagerUnsetchangelistener(const picojson::value& a
// CHECK_PRIVILEGE_ACCESS(kPrivilegeContentRead, &out);
CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
- if (ContentManager::getInstance()->unSetChangeListener().IsError()) {
- LoggerD("unsuccesfull deregistering of callback");
- }
if (ContentManager::getInstance()->removeChangeListener(noti_handle_).IsError()) {
LoggerD("unsuccesfull deregistering of callback");
} else {
@@ -791,17 +734,37 @@ void ContentInstance::ContentManagerCreateThumbnail(const picojson::value& args,
picojson::object& out) {
ScopeLogger();
CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
- common::PlatformResult result = common::PlatformResult(common::ErrorCode::NO_ERROR);
-
- if (ContentManager::getInstance()->isConnected()) {
- result = ContentManager::getInstance()->createThumbnail(args);
- } else {
- result = LogAndCreateResult(common::ErrorCode::UNKNOWN_ERR, "DB Connection is failed.");
- }
- if (!result) {
- LogAndReportError(result, &out, ("Failed to create a thumbnail"));
- common::Instance::PostMessage(this, picojson::value(out).serialize().c_str());
+ double callback_id = args.get("callbackId").get<double>();
+
+ if (not ContentManager::getInstance()->isConnected()) {
+ TaskQueue::GetInstance().Async([this, callback_id]() {
+ PlatformResult result =
+ LogAndCreateResult(common::ErrorCode::ABORT_ERR, "DB Connection is not established.");
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj.emplace("callbackId", picojson::value(callback_id));
+ LogAndReportError(result, &obj, ("DB Connection is not established."));
+ Instance::PostMessage(this, response.serialize().c_str());
+ });
+ return;
}
+
+ const std::string& id = args.get("id").get<std::string>();
+ auto work = [this, id, callback_id]() {
+ ScopeLogger();
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj.emplace("callbackId", picojson::value(callback_id));
+ auto result = ContentManager::getInstance()->createThumbnail(id, &obj);
+ if (result) {
+ ReportSuccess(obj);
+ } else {
+ LogAndReportError(result, &obj);
+ }
+ Instance::PostMessage(this, response.serialize().c_str());
+ };
+ TaskQueue::GetInstance().Async(work);
+ ReportSuccess(out);
}
void ContentInstance::ContentManagerPlaylistAdd(const picojson::value& args,
@@ -945,6 +908,11 @@ void ContentInstance::ContentManagerAudioGetLyrics(const picojson::value& args,
picojson::object& out) {
ScopeLogger();
+ const std::string& contentURI = args.get("contentURI").get<std::string>();
+ const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(contentURI);
+
+ CHECK_STORAGE_ACCESS(real_path, &out);
+
picojson::object lyrics;
if (ContentManager::getInstance()->isConnected()) {
int ret = ContentManager::getInstance()->getLyrics(args, lyrics);
@@ -1013,6 +981,10 @@ void ContentInstance::PlaylistSetThumbnailUri(const picojson::value& args, picoj
CHECK_EXIST(args, "uri", out)
int id = static_cast<int>(args.get("id").get<double>());
std::string uri = args.get("uri").get<std::string>();
+ const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(uri);
+
+ CHECK_STORAGE_ACCESS(real_path, &out);
+
ret = ContentManager::getInstance()->setThumbnailUri(id, uri);
if (ret != MEDIA_CONTENT_ERROR_NONE) {
LogAndReportError(ContentManager::getInstance()->convertError(ret), &out);
diff --git a/src/content/content_manager.cc b/src/content/content_manager.cc
index 9c069ed1..86e2655d 100644
--- a/src/content/content_manager.cc
+++ b/src/content/content_manager.cc
@@ -644,38 +644,6 @@ static bool playlist_content_member_cb(int playlist_member_id, media_info_h medi
return true;
}
-void CreateThumbnailCallback(media_content_error_e err, const char* path, void* user_data) {
- ScopeLogger();
-
- std::unique_ptr<CreateThumbnailCallbackData> callback_data_ptr(
- (CreateThumbnailCallbackData*)user_data);
- if (0 == callback_data_ptr->callback_id) {
- LoggerD("Callback id is 0");
- return;
- }
-
- if (!(ContentManager::getInstance()->getContentInstance())) {
- // There is not instance already
- LoggerD("There is not instance now");
- return;
- }
-
- picojson::object out;
-
- out["callbackId"] = picojson::value(callback_data_ptr->callback_id);
-
- if (MEDIA_CONTENT_ERROR_NONE == err) {
- out["result"] = picojson::value(std::string(path));
- ReportSuccess(out);
- } else {
- PlatformResult result = ContentManager::getInstance()->convertError(err);
- LogAndReportError(result, &out, ("Failed to create a thumbnail"));
- }
-
- common::Instance::PostMessage(ContentManager::getInstance()->getContentInstance(),
- picojson::value(out).serialize().c_str());
-}
-
ContentManager::ContentManager() {
ScopeLogger("ContentManager called");
if (media_content_connect() == MEDIA_CONTENT_ERROR_NONE) {
@@ -910,31 +878,6 @@ PlatformResult ContentManager::removeChangeListener(media_content_noti_h noti_ha
}
}
-PlatformResult ContentManager::setChangeListener(media_content_db_update_cb callback,
- void* user_data) {
- ScopeLogger();
-
- int ret = media_content_set_db_updated_cb(callback, user_data);
- if (ret != MEDIA_CONTENT_ERROR_NONE) {
- return LogAndCreateResult(
- ErrorCode::UNKNOWN_ERR, "registering the listener is failed.",
- ("Failed: registering the listener is failed %d (%s)", ret, get_error_message(ret)));
- }
- return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult ContentManager::unSetChangeListener() {
- ScopeLogger();
-
- int ret = media_content_unset_db_updated_cb();
- if (ret != MEDIA_CONTENT_ERROR_NONE) {
- return LogAndCreateResult(
- ErrorCode::UNKNOWN_ERR, "unregistering the listener is failed.",
- ("Failed: unregistering the listener is failed: %d (%s)", ret, get_error_message(ret)));
- }
- return PlatformResult(ErrorCode::NO_ERROR);
-}
-
void ContentManager::createPlaylist(std::string name,
const std::shared_ptr<ReplyCallbackData>& user_data) {
ScopeLogger();
@@ -1602,27 +1545,35 @@ int ContentManager::getNumberOfTracks(int id, int* result) {
return MEDIA_CONTENT_ERROR_NONE;
}
-common::PlatformResult ContentManager::createThumbnail(const picojson::value& args) {
+common::PlatformResult ContentManager::createThumbnail(const std::string& id,
+ picojson::object* obj) {
ScopeLogger();
- std::unique_ptr<CreateThumbnailCallbackData> callback_data_ptr{new CreateThumbnailCallbackData};
- callback_data_ptr->callback_id = args.get("callbackId").get<double>();
- std::string id = args.get("id").get<std::string>();
-
- int ret = media_info_get_media_from_db(id.c_str(), &callback_data_ptr->media);
- if (MEDIA_CONTENT_ERROR_NONE != ret && nullptr == callback_data_ptr->media) {
- return LogAndCreateResult(ErrorCode::ABORT_ERR, "Getting media is failed.",
- ("Getting media is failed: %d (%s)", ret, get_error_message(ret)));
+ media_info_h media_h = nullptr;
+ int ret = media_info_get_media_from_db(id.c_str(), &media_h);
+ if (MEDIA_CONTENT_ERROR_NONE != ret || nullptr == media_h) {
+ return LogAndCreateResult(ErrorCode::ABORT_ERR, "Getting media failed.",
+ ("Getting media failed: %d (%s)", ret, get_error_message(ret)));
}
+ SCOPE_EXIT {
+ media_info_destroy(media_h);
+ };
- ret = media_info_create_thumbnail(callback_data_ptr->media, CreateThumbnailCallback,
- static_cast<void*>(callback_data_ptr.get()));
-
+ ret = media_info_generate_thumbnail(media_h);
if (MEDIA_CONTENT_ERROR_NONE != ret) {
return LogAndCreateResult(ErrorCode::ABORT_ERR, "Creating thumbnail failed.",
("Creating thumbnail failed: %d (%s)", ret, get_error_message(ret)));
}
- callback_data_ptr.release();
+
+ char* path = nullptr;
+ ret = media_info_get_thumbnail_path(media_h, &path);
+ if (MEDIA_CONTENT_ERROR_NONE != ret) {
+ return LogAndCreateResult(
+ ErrorCode::ABORT_ERR, "Creating thumbnail succeeded, but failed to get thumbnail path.",
+ ("Getting thumbnail path failed: %d (%s)", ret, get_error_message(ret)));
+ }
+ obj->emplace("result", picojson::value(path));
+ std::unique_ptr<char[], decltype(&free)>(path, free);
return PlatformResult(ErrorCode::NO_ERROR);
}
diff --git a/src/content/content_manager.h b/src/content/content_manager.h
index 1801ec41..af8efa76 100644
--- a/src/content/content_manager.h
+++ b/src/content/content_manager.h
@@ -38,14 +38,6 @@ typedef std::unique_ptr<std::remove_pointer<media_playlist_h>::type, void (*)(me
void ContentToJson(media_info_h info, picojson::object& o);
void ContentDirToJson(media_folder_h folder, picojson::object& o);
-struct CreateThumbnailCallbackData {
- double callback_id;
- media_info_h media;
- ~CreateThumbnailCallbackData() {
- media_info_destroy(media);
- }
-};
-
class ContentManager {
public:
virtual ~ContentManager();
@@ -65,8 +57,6 @@ class ContentManager {
common::PlatformResult addChangeListener(media_content_noti_h* noti_handle,
media_content_db_update_cb callback, void* user_data);
common::PlatformResult removeChangeListener(media_content_noti_h noti_handle);
- common::PlatformResult setChangeListener(media_content_db_update_cb callback, void* user_data);
- common::PlatformResult unSetChangeListener();
// Lyrics
int getLyrics(const picojson::value& args, picojson::object& result);
@@ -93,7 +83,7 @@ class ContentManager {
// thumbnail
int getThumbnailUri(int id, std::string* result);
int setThumbnailUri(int id, const std::string& thb_uri);
- common::PlatformResult createThumbnail(const picojson::value& args);
+ common::PlatformResult createThumbnail(const std::string& id, picojson::object* obj);
private:
// int setContent(media_info_h media, picojson::value content);
diff --git a/src/content/js/datatypes.js b/src/content/js/datatypes.js
index 1f8ec435..9ddfd0dd 100755
--- a/src/content/js/datatypes.js
+++ b/src/content/js/datatypes.js
@@ -483,6 +483,10 @@ function AudioContent(data) {
if (native_.isFailure(result)) {
utils_.log('Getting lyrics failed for ' + data.contentURI);
+ var error_object = native_.getErrorObject(result);
+ if (WebAPIException.SECURITY_ERR == error_object.code) {
+ throw error_object;
+ }
return;
}
diff --git a/src/content/js/manager.js b/src/content/js/manager.js
index 26f2964d..3c585458 100755
--- a/src/content/js/manager.js
+++ b/src/content/js/manager.js
@@ -406,9 +406,8 @@ ContentManager.prototype.removeChangeListener = function() {
ContentManager.prototype.setChangeListener = function(changeCallback) {
privUtils_.warn(
- 'DEPRECATION WARNING: setChangeListener() is deprecated ' +
- 'and will be removed from next release. ' +
- 'Use addChangeListener() instead.'
+ 'DEPRECATION WARNING: setChangeListener() is deprecated and will be removed ' +
+ 'from next release. Use addChangeListener() instead.'
);
var args = validator_.validateArgs(arguments, [
@@ -455,9 +454,8 @@ ContentManager.prototype.setChangeListener = function(changeCallback) {
ContentManager.prototype.unsetChangeListener = function() {
privUtils_.warn(
- 'DEPRECATION WARNING: unsetChangeListener() ' +
- 'is deprecated and will be removed from next release. ' +
- 'Use removeChangeListener() instead.'
+ 'DEPRECATION WARNING: unsetChangeListener() is deprecated and will be removed ' +
+ 'from next release. Use removeChangeListener() instead.'
);
var data = {};
diff --git a/src/content/js/playlist.js b/src/content/js/playlist.js
index 3b8ab05a..14ff1fab 100755
--- a/src/content/js/playlist.js
+++ b/src/content/js/playlist.js
@@ -75,19 +75,19 @@ function Playlist(data) {
throw native_.getErrorObject(result);
}
var res = native_.getResultObject(result);
- //CoreAPI not support empty thumbnail,
- //so one space must be used instead null thumbnail
+ //CoreAPI not support empty thumbnail, so one space must be used instead
+ //null thumbnail
return res === ' ' ? null : res;
},
set: function(v) {
var thumbnailURI = converter_.toString(v, true);
if (type_.isNullOrUndefined(thumbnailURI)) {
- //CoreAPI not support empty thumbnail,
- //so one space must be used instead null thumbnail
+ //CoreAPI not support empty thumbnail, so one space must be used
+ //instead null thumbnail
thumbnailURI = ' ';
}
- //TODO probably thumbnailURI should be converted here
- //to absolute uri in case of virtual
+ //TODO probably thumbnailURI should be converted here to absolute uri
+ //in case of virtual
var result = native_.callSync('ContentPlaylist_setThumbnailUri', {
id: Number(id),
uri: thumbnailURI
diff --git a/src/datacontrol/datacontrol_api.js b/src/datacontrol/datacontrol_api.js
index 94bf83b9..18ff77fc 100755
--- a/src/datacontrol/datacontrol_api.js
+++ b/src/datacontrol/datacontrol_api.js
@@ -249,12 +249,10 @@ var getDataControlConsumer = function(providerId, dataId, type) {
returnObject = new MappedDataControlConsumer();
}
- // read only property
- SetReadOnlyProperty(returnObject, 'type', args.type);
- // read only property
- SetReadOnlyProperty(returnObject, 'providerId', args.providerId);
- // read only property
- SetReadOnlyProperty(returnObject, 'dataId', args.dataId);
+ SetReadOnlyProperty(returnObject, 'type', args.type); // read only property
+ SetReadOnlyProperty(returnObject, 'providerId', args.providerId); // read only
+ // property
+ SetReadOnlyProperty(returnObject, 'dataId', args.dataId); // read only property
return returnObject;
};
diff --git a/src/download/download_instance.cc b/src/download/download_instance.cc
index f33102c5..0ebd945a 100644
--- a/src/download/download_instance.cc
+++ b/src/download/download_instance.cc
@@ -571,6 +571,11 @@ void DownloadInstance::DownloadManagerStart(const picojson::value& args, picojso
}
}
+ CHECK_STORAGE_ACCESS(di_ptr->destination.empty()
+ ? common::FilesystemProvider::Create().GetRealPath("downloads")
+ : di_ptr->destination,
+ &out);
+
if (!args.get("fileName").is<picojson::null>()) {
if (args.get("fileName").is<std::string>() && args.get("fileName").get<std::string>() != "") {
di_ptr->file_name = args.get("fileName").get<std::string>();
diff --git a/src/exif/exif_api.js b/src/exif/exif_api.js
index bd732e18..841ad213 100644
--- a/src/exif/exif_api.js
+++ b/src/exif/exif_api.js
@@ -231,7 +231,12 @@ ExifManager.prototype.getExifInfo = function() {
}
};
- native_.call('ExifManager_getExifInfo', { uri: args.uri }, callback);
+ var result = native_.call('ExifManager_getExifInfo', { uri: args.uri }, callback);
+
+ if (native_.isFailure(result)) {
+ // since tizen 5.0 the only possible error type here is SecurityError
+ throw native_.getErrorObject(result);
+ }
};
ExifManager.prototype.saveExifInfo = function() {
@@ -257,7 +262,7 @@ ExifManager.prototype.saveExifInfo = function() {
}
]);
- if (!_isValidAbsoluteURI(args.exifInfo.uri)) {
+ if (!args.exifInfo.uri || !_isValidAbsoluteURI(args.exifInfo.uri)) {
setTimeout(function() {
native_.callIfPossible(
args.errorCallback,
@@ -277,7 +282,12 @@ ExifManager.prototype.saveExifInfo = function() {
}
};
- native_.call('ExifManager_saveExifInfo', json, callback);
+ var result = native_.call('ExifManager_saveExifInfo', json, callback);
+
+ if (native_.isFailure(result)) {
+ // since tizen 5.0 the only possible error type here is SecurityError
+ throw native_.getErrorObject(result);
+ }
};
ExifManager.prototype.getThumbnail = function() {
@@ -321,22 +331,18 @@ ExifManager.prototype.getThumbnail = function() {
}
};
- native_.call('ExifManager_getThumbnail', { uri: args.uri }, _callback);
+ var result = native_.call('ExifManager_getThumbnail', { uri: args.uri }, _callback);
+
+ if (native_.isFailure(result)) {
+ // since tizen 5.0 the only possible error type here is SecurityError
+ throw native_.getErrorObject(result);
+ }
};
-tizen.ExifInformation = function() {
+tizen.ExifInformation = function(exifInitDict) {
validator_.isConstructorCall(this, tizen.ExifInformation);
- var args = validator_.validateArgs(arguments, [
- {
- name: 'ExifInitDict',
- type: validator_.Types.DICTIONARY,
- optional: true,
- nullable: false
- }
- ]);
-
- var uri_ = null,
+ var uri_ = '',
width_ = null,
height_ = null,
deviceMaker_ = null,
@@ -356,16 +362,6 @@ tizen.ExifInformation = function() {
gpsTime_ = null,
userComment_ = null;
- var exifInitDict = args.ExifInitDict;
- if (exifInitDict) {
- if (exifInitDict.uri === null) {
- throw new WebAPIException(
- WebAPIException.INVALID_VALUES_ERR,
- 'Parameter "uri" is required.'
- );
- }
- }
-
Object.defineProperties(this, {
uri: {
get: function() {
@@ -526,9 +522,8 @@ tizen.ExifInformation = function() {
},
set: function(v) {
if (!type_.isUndefined(v)) {
- if (v === null || v instanceof tizen.SimpleCoordinates) {
+ if (v === null || v instanceof tizen.SimpleCoordinates)
gpsLocation_ = v;
- }
}
},
enumerable: true
@@ -562,9 +557,8 @@ tizen.ExifInformation = function() {
},
set: function(v) {
if (!type_.isUndefined(v)) {
- if (v === null || v instanceof Date || v instanceof tizen.TZDate) {
+ if (v === null || v instanceof Date || v instanceof tizen.TZDate)
gpsTime_ = v;
- }
}
}
},
diff --git a/src/exif/exif_information.cc b/src/exif/exif_information.cc
index 9a07286b..6ed1bcc5 100644
--- a/src/exif/exif_information.cc
+++ b/src/exif/exif_information.cc
@@ -333,7 +333,7 @@ void ExifInformation::setGpsProcessingMethod(const std::string& type,
const std::string& processing_method) {
if (type != EXIF_UNDEFINED_TYPE_ASCII && type != EXIF_UNDEFINED_TYPE_JIS &&
type != EXIF_UNDEFINED_TYPE_UNICODE && type != EXIF_UNDEFINED_TYPE_UNDEFINED) {
- LoggerW("Trying to set invalid GPSProcessingMethod type: [%s] len:%d", type.c_str(),
+ LoggerW("Trying to set invalid GPSProcessingMethod type: [%s] len: %zu", type.c_str(),
type.length());
return;
}
@@ -368,7 +368,7 @@ const std::string& ExifInformation::getUserCommentType() {
void ExifInformation::setUserComment(const std::string& type, const std::string& user_comment) {
if (type != EXIF_UNDEFINED_TYPE_ASCII && type != EXIF_UNDEFINED_TYPE_JIS &&
type != EXIF_UNDEFINED_TYPE_UNICODE && type != EXIF_UNDEFINED_TYPE_UNDEFINED) {
- LoggerW("Trying to set invalid user comment type: [%s] len:%d", type.c_str(), type.length());
+ LoggerW("Trying to set invalid user comment type: [%s] len: %zu", type.c_str(), type.length());
return;
}
@@ -689,7 +689,7 @@ PlatformResult ExifInformation::updateAttributesInExifData(ExifData* exif_data)
}
if (isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) {
std::vector<long long int> iso_ratings = getIsoSpeedRatings();
- LoggerD("Saving iso speed ratings count:%d", iso_ratings.size());
+ LoggerD("Saving iso speed ratings count: %zu", iso_ratings.size());
ret = ExifTagSaver::saveToExif(iso_ratings, EXIF_FORMAT_SHORT, EXIF_TAG_ISO_SPEED_RATINGS,
exif_data);
if (!ret) {
diff --git a/src/exif/exif_instance.cc b/src/exif/exif_instance.cc
index 0687d700..28ae74c1 100644
--- a/src/exif/exif_instance.cc
+++ b/src/exif/exif_instance.cc
@@ -20,9 +20,11 @@
#include <libexif/exif-loader.h>
#include <libexif/exif-utils.h>
+#include <glib.h>
#include <sstream>
#include <string>
+#include "common/filesystem/filesystem_provider.h"
#include "common/logger.h"
#include "common/platform_result.h"
#include "common/task-queue.h"
@@ -59,15 +61,18 @@ void ExifInstance::ExifManagerGetExifInfo(const picojson::value& args, picojson:
ScopeLogger();
const std::string& uri = args.get("uri").get<std::string>();
+ const std::string& file_path = ExifUtil::convertUriToPath(uri);
const double callback_id = args.get("callbackId").get<double>();
+ const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(file_path);
+
+ CHECK_STORAGE_ACCESS(real_path, &out);
+
auto get = [=](const std::shared_ptr<JsonValue>& response) -> void {
ScopeLogger("Entered into asynchronous function, get");
JsonValue result = JsonValue(JsonObject());
PlatformResult status(ErrorCode::NO_ERROR);
- const std::string& file_path = ExifUtil::convertUriToPath(uri);
-
PlatformResult fileAvailability(common::tools::CheckFileAvailability(file_path));
if (!fileAvailability) {
LogAndReportError(fileAvailability, &response->get<picojson::object>());
@@ -99,15 +104,20 @@ void ExifInstance::ExifManagerSaveExifInfo(const picojson::value& args, picojson
ScopeLogger();
const double callback_id = args.get("callbackId").get<double>();
+
+ const std::string& file_uri = args.get("uri").get<std::string>();
+ const std::string& file_path = ExifUtil::convertUriToPath(file_uri);
+ const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(file_path);
+
+ CHECK_STORAGE_ACCESS(real_path, &out);
+
auto get = [=](const std::shared_ptr<JsonValue>& response) -> void {
ScopeLogger("Entered into asynchronous function, get");
JsonValue result = JsonValue(JsonObject());
PlatformResult status(ErrorCode::NO_ERROR);
ExifInformationPtr exifInfo(new ExifInformation(args));
- const std::string& uri = exifInfo->getUri();
- const std::string& path = ExifUtil::convertUriToPath(uri);
- status = exifInfo->saveToFile(path);
+ status = exifInfo->saveToFile(file_path);
if (status)
ReportSuccess(result, response->get<picojson::object>());
@@ -131,12 +141,16 @@ void ExifInstance::ExifManagerGetThumbnail(const picojson::value& args, picojson
ScopeLogger();
const std::string& uri = args.get("uri").get<std::string>();
+ const std::string& file_path = ExifUtil::ExifUtil::convertUriToPath(uri);
+ const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(file_path);
+
+ CHECK_STORAGE_ACCESS(real_path, &out);
+
const double callback_id = args.get("callbackId").get<double>();
auto get = [=](const std::shared_ptr<JsonValue>& response) -> void {
ScopeLogger("Entered into asynchronous function, get");
PlatformResult status(ErrorCode::NO_ERROR);
- const std::string& file_path = ExifUtil::convertUriToPath(uri);
JsonValue result = JsonValue(JsonObject());
JsonObject& result_obj = result.get<JsonObject>();
diff --git a/src/exif/exif_tag_saver.cc b/src/exif/exif_tag_saver.cc
index 0d917669..74b8092f 100644
--- a/src/exif/exif_tag_saver.cc
+++ b/src/exif/exif_tag_saver.cc
@@ -31,7 +31,7 @@ void ExifTagSaver::removeExifEntryWithTag(const ExifTag tag, ExifData* exif_data
ScopeLogger("tag: %d (%p)", tag, exif_data);
ExifEntry* exif_entry = exif_data_get_entry(exif_data, tag);
if (!exif_entry) {
- LoggerE("Exif entry with tag: %d (0x%x) is not present", tag, tag);
+ LoggerE("Exif entry with tag: %d (0x%x) is not present", tag, (unsigned)tag);
return;
}
diff --git a/src/exif/get_exif_info.cc b/src/exif/get_exif_info.cc
index a5e4e81c..4cd21c48 100644
--- a/src/exif/get_exif_info.cc
+++ b/src/exif/get_exif_info.cc
@@ -85,7 +85,7 @@ bool DecomposeExifUndefined(ExifEntry* entry, std::string& type, std::string& va
}
if (entry->size < EXIF_UNDEFINED_TYPE_LENGTH) {
- LoggerW("entry size is invalid %d < EXIF_UNDEFINED_TYPE_LENGTH", entry->size);
+ LoggerW("entry size is invalid %u < EXIF_UNDEFINED_TYPE_LENGTH", entry->size);
return false;
}
@@ -313,7 +313,7 @@ PlatformResult GetExifInfo::ProcessEntry(ExifEntry* entry, ExifData* exif_data,
result_obj->insert(pair);
LoggerD("Setting ExifInformation gps longitude REF to: WEST");
} else {
- LoggerW("Unknown longitude ref: %c (0x%x)", ref, static_cast<int>(ref));
+ LoggerW("Unknown longitude ref: %c (0x%x)", ref, static_cast<unsigned>(ref));
}
break;
}
@@ -357,7 +357,7 @@ PlatformResult GetExifInfo::ProcessEntry(ExifEntry* entry, ExifData* exif_data,
result_obj->insert(pair);
LoggerD("Setting ExifInformation gps latitude REF to: SOUTH");
} else {
- LoggerW("Unknown latitude ref: %c (0x%x)", ref, static_cast<int>(ref));
+ LoggerW("Unknown latitude ref: %c (0x%x)", ref, static_cast<unsigned>(ref));
}
break;
}
@@ -390,7 +390,7 @@ PlatformResult GetExifInfo::ProcessEntry(ExifEntry* entry, ExifData* exif_data,
// UNDEFINED - Any
std::string type, value;
if (DecomposeExifUndefined(entry, type, value)) {
- LoggerD("Extracted GPSProcessingMethod: [%s], len:%d, type:%s", value.c_str(),
+ LoggerD("Extracted GPSProcessingMethod: [%s], len: %zu, type: %s", value.c_str(),
value.length(), type.c_str());
pair = std::make_pair("gpsProcessingMethod", JsonValue(value));
result_obj->insert(pair);
@@ -425,7 +425,7 @@ PlatformResult GetExifInfo::ProcessEntry(ExifEntry* entry, ExifData* exif_data,
// UNDEFINED - Any
std::string type, value;
if (DecomposeExifUndefined(entry, type, value)) {
- LoggerD("Extracted UserComment: [%s], len:%d, type:%s", value.c_str(), value.length(),
+ LoggerD("Extracted UserComment: [%s], len: %zu, type: %s", value.c_str(), value.length(),
type.c_str());
pair = std::make_pair("userComment", JsonValue(value));
diff --git a/src/exif/jpeg_file.cc b/src/exif/jpeg_file.cc
index 5fe598dc..8c5e4746 100644
--- a/src/exif/jpeg_file.cc
+++ b/src/exif/jpeg_file.cc
@@ -167,7 +167,7 @@ PlatformResult JpegFile::load(const std::string& path) {
("fseek failed with error! [%d]", res));
}
- LoggerD("JPEG file: [%s] size:%d", path.c_str(), in_file_size);
+ LoggerD("JPEG file: [%s] size: %zu", path.c_str(), in_file_size);
if (0 == in_file_size) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "JPEG file is invalid",
("Input file [%s] is empty!", path.c_str()));
@@ -176,7 +176,7 @@ PlatformResult JpegFile::load(const std::string& path) {
m_in_data = new (std::nothrow) unsigned char[in_file_size];
if (!m_in_data) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Memory allocation failed",
- ("Couldn't allocate buffer with size: %d", in_file_size));
+ ("Couldn't allocate buffer with size: %zu", in_file_size));
}
m_in_data_size = in_file_size;
@@ -185,7 +185,7 @@ PlatformResult JpegFile::load(const std::string& path) {
if (read_bytes != m_in_data_size) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Could not read JPEG file",
- ("Couldn't read all: %d bytes. Read only: %u bytes!", m_in_data_size, read_bytes));
+ ("Couldn't read all: %zu bytes. Read only: %zu bytes!", m_in_data_size, read_bytes));
}
if (fclose(m_in_file) == EOF) {
@@ -241,7 +241,7 @@ common::PlatformResult JpegFile::generateListOfSections() {
m_padding_data_size = 0;
for (size_t offset = 0, iterration = 0; offset < m_in_data_size; ++iterration) {
- LoggerD("offset:%u | Starting iteration: %u", offset, iterration);
+ LoggerD("offset: %zu | Starting iteration: %zu", offset, iterration);
const std::size_t search_len = 10;
std::size_t search_offset = 0;
for (search_offset = 0; search_offset < search_len; ++search_offset) {
@@ -254,7 +254,7 @@ common::PlatformResult JpegFile::generateListOfSections() {
if (search_len == search_offset) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "JPEG file is invalid",
- ("offset:%u | Couldn't find marker! RAW DATA:{%s}", offset,
+ ("offset: %zu | Couldn't find marker! RAW DATA:{%s}", offset,
getPartOfFile(offset, 0, 10).c_str()));
}
@@ -262,16 +262,16 @@ common::PlatformResult JpegFile::generateListOfSections() {
unsigned char* section_begin = m_in_data + section_offset;
offset = section_offset; // Move to section begin
- LoggerD("offset:%u | Moved to section begin", offset);
+ LoggerD("offset: %zu | Moved to section begin", offset);
if (!isJpegMarker(section_begin[1])) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "JPEG file is invalid",
- ("offset:%u | Is not valid marker: 0x%x RAW DATA:{%s}", offset,
+ ("offset: %zu | Is not valid marker: 0x%x RAW DATA:{%s}", offset,
section_begin[1], getPartOfFile(section_offset, 0, 4).c_str()));
}
const JpegMarker cur_marker = castToJpegMarker(section_begin[1]);
- LoggerD("offset:%u | Found valid marker: 0x%x RAW DATA:{%s}", offset, cur_marker,
+ LoggerD("offset: %zu | Found valid marker: 0x%x RAW DATA:{%s}", offset, (unsigned)cur_marker,
getPartOfFile(section_offset, 0, 4).c_str());
offset += 2; // Read 0xffxx marker tag - 2 bytes
@@ -290,7 +290,7 @@ common::PlatformResult JpegFile::generateListOfSections() {
section->type = cur_marker;
m_sections.push_back(section);
if (cur_marker == JPEG_MARKER_SOI || cur_marker == JPEG_MARKER_EOI) {
- LoggerD("offset:%u | Found: %s marker, moving to next marker at:%u", section_offset,
+ LoggerD("offset: %zu | Found: %s marker, moving to next marker at: %zu", section_offset,
((cur_marker == JPEG_MARKER_SOI) ? "SOI" : "EOI"), offset);
if (cur_marker == JPEG_MARKER_EOI && m_padding_data != NULL) {
@@ -317,23 +317,23 @@ common::PlatformResult JpegFile::generateListOfSections() {
// size 2 bytes
const long section_data_len = total_section_len - 2;
- LoggerD("offset:%u tag:0x%x | Read total_section_len:%ld (data len:%ld)", section_offset,
- cur_marker, total_section_len, section_data_len);
+ LoggerD("offset: %zu tag:0x%x | Read total_section_len: %ld (data len: %ld)", section_offset,
+ (unsigned)cur_marker, total_section_len, section_data_len);
offset += 2; // Read data size - 2 bytes
if (total_section_len < 0) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "JPEG file is invalid",
- ("offset:%u tag:0x%x | Error: total_section_len is: %ld < 0",
- offset, cur_marker, total_section_len));
+ ("offset: %zu tag:0x%x | Error: total_section_len is: %ld < 0",
+ offset, (unsigned)cur_marker, total_section_len));
}
if (section_offset + 2 + total_section_len > m_in_data_size) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "JPEG file is invalid",
- ("offset:%u tag:0x%x | Error: current section offset:%u"
- " + 2 + total_section_len:%ld = %lu is greater then file size:%u",
- offset, cur_marker, section_offset, total_section_len,
+ ("offset: %zu tag:0x%x | Error: current section offset: %zu"
+ " + 2 + total_section_len: %ld = %lu is greater then file size: %zu",
+ offset, (unsigned)cur_marker, section_offset, total_section_len,
section_offset + total_section_len, m_in_data_size));
}
@@ -342,12 +342,12 @@ common::PlatformResult JpegFile::generateListOfSections() {
section->exif_data = exif_data_new_from_data(section_begin, exif_data_size);
LoggerD(
- "offset:%u tag:0x%x | Loading exif from offset:%u"
- " len:%u exif_data_new_from_data returned: %p",
- offset, cur_marker, section_offset, exif_data_size, section->exif_data);
+ "offset: %zu tag:0x%x | Loading exif from offset: %zu"
+ " len: %u exif_data_new_from_data returned: %p",
+ offset, (unsigned)cur_marker, section_offset, exif_data_size, section->exif_data);
if (!section->exif_data) {
- LoggerW("offset:%d tag:0x%x | Couldn't load Exif!", offset, cur_marker);
+ LoggerW("offset: %zu tag:0x%x | Couldn't load Exif!", offset, (unsigned)cur_marker);
}
}
@@ -367,9 +367,9 @@ common::PlatformResult JpegFile::generateListOfSections() {
// -2 (exclude ending EOI marker (2 bytes)
std::size_t image_size = m_in_data_size - image_data_offset - 2;
LoggerW(
- "offset:%d tag:0x%x"
- " | Image data offset:%u Estimated image size:%u",
- offset, cur_marker, image_data_offset, image_size);
+ "offset: %zu tag:0x%x"
+ " | Image data offset: %zu Estimated image size: %zu",
+ offset, (unsigned)cur_marker, image_data_offset, image_size);
m_image_data = m_in_data + image_data_offset;
@@ -384,31 +384,32 @@ common::PlatformResult JpegFile::generateListOfSections() {
"JPEG file contains image data stream: image_size+= 2");
image_size += 2; // Skip expected EOI tag which is not present
} else {
- LoggerD("EOI tag found at offset: %d from SOS data", eoi_tag_index);
+ LoggerD("EOI tag found at offset: %zu from SOS data", eoi_tag_index);
if (eoi_tag_index != image_size) {
LoggerW(
- "Estimated image size:%d doesn't match EOI tag index:%d"
- " delta:%d",
+ "Estimated image size: %zu doesn't match EOI tag index: %zu"
+ " delta: %zu",
image_size, eoi_tag_index, image_size - eoi_tag_index);
- LoggerW("Setting image_size to EOI tag: %u", eoi_tag_index);
+ LoggerW("Setting image_size to EOI tag: %zu", eoi_tag_index);
image_size = eoi_tag_index;
m_padding_data = m_image_data + image_size + 2; // (skip EOI tag)
m_padding_data_size = (m_in_data + m_in_data_size) - m_padding_data;
- LoggerW("Saving padding data from offset:%d with size:%d", m_padding_data - m_in_data,
- m_padding_data_size);
+ LoggerW("Saving padding data from offset: %td with size: %zu",
+ m_padding_data - m_in_data, m_padding_data_size);
}
}
m_image_size = image_size;
offset = image_data_offset + image_size;
- LoggerD("offset:%u tag:0x%x | SOS Offset moved to next marker", offset, cur_marker);
+ LoggerD("offset: %zu tag:0x%x | SOS Offset moved to next marker", offset,
+ (unsigned)cur_marker);
} else {
offset += section_data_len;
- LoggerD("offset:%u tag:0x%x | Offset moved to next marker", offset, cur_marker);
+ LoggerD("offset: %zu tag:0x%x | Offset moved to next marker", offset, (unsigned)cur_marker);
}
}
}
@@ -419,7 +420,7 @@ common::PlatformResult JpegFile::generateListOfSections() {
bool JpegFile::searchForTagInBuffer(const unsigned char* buffer_start,
const unsigned char* buffer_end, const JpegMarker marker,
std::size_t& out_index) {
- ScopeLogger("start:%p end:%p marker:0x%x", buffer_start, buffer_end, marker);
+ ScopeLogger("start: %p end: %p marker:0x%x", buffer_start, buffer_end, (unsigned)marker);
if (!buffer_start) {
LoggerE("buffer_start is NULL");
@@ -436,7 +437,7 @@ bool JpegFile::searchForTagInBuffer(const unsigned char* buffer_start,
return false;
}
- LoggerD("Bytes to scan: %d", static_cast<size_t>(buffer_end - buffer_start));
+ LoggerD("Bytes to scan: %zu", static_cast<size_t>(buffer_end - buffer_start));
const unsigned char marker_uchar = static_cast<unsigned char>(marker);
for (const unsigned char* ptr = buffer_start; ptr < buffer_end; ++ptr) {
@@ -520,7 +521,7 @@ ExifData* JpegFile::getExifData() {
}
PlatformResult JpegFile::saveToFile(const std::string& out_path) {
- ScopeLogger("out_path:%s", out_path.c_str());
+ ScopeLogger("out_path: %s", out_path.c_str());
PlatformResult status = saveToFilePriv(out_path);
if (status) return status;
@@ -549,7 +550,7 @@ PlatformResult JpegFile::saveToFile(const std::string& out_path) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Couldn't restore whole file",
("Couldn't restore whole JPEG! "
- "Only %d of %d bytes have been wrote!",
+ "Only %zu of %zu bytes have been wrote!",
bytes_wrote, m_in_data_size));
}
if (EOF == fclose(outf)) {
@@ -563,7 +564,7 @@ PlatformResult JpegFile::saveToFile(const std::string& out_path) {
}
PlatformResult JpegFile::saveToFilePriv(const std::string& out_path) {
- ScopeLogger("out_path:%s", out_path.c_str());
+ ScopeLogger("out_path: %s", out_path.c_str());
m_out_file = fopen(out_path.c_str(), "wb");
if (!m_out_file) {
@@ -580,7 +581,7 @@ PlatformResult JpegFile::saveToFilePriv(const std::string& out_path) {
JpegFileSectionPtr cur = *it;
const JpegMarker cur_marker = cur->type;
- LoggerD("offset:%d | Section: %d marker 0x%x", offset, section_index, cur_marker);
+ LoggerD("offset: %zu | Section: %d marker 0x%x", offset, section_index, (unsigned)cur_marker);
std::size_t bytes_to_write = 0;
std::size_t bytes_wrote = 0;
@@ -604,15 +605,15 @@ PlatformResult JpegFile::saveToFilePriv(const std::string& out_path) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Could not save Exif in JPEG file");
}
- LoggerD("offset:%d | Generated Exif RAW Data length:%d", offset, exif_output_size);
+ LoggerD("offset: %zu | Generated Exif RAW Data length: %u", offset, exif_output_size);
exif_output_data.reset(tmp);
if (exif_output_size > MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
"Exif data is to big to be saved in JPEG file",
- ("exif_output_size:%d is greater then maximum JPEG section"
- "data block size: %d",
+ ("exif_output_size: %u is greater then maximum JPEG section"
+ "data block size: %u",
exif_output_size, MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE));
}
section_size += exif_output_size;
@@ -627,9 +628,9 @@ PlatformResult JpegFile::saveToFilePriv(const std::string& out_path) {
}
LoggerD(
- "offset:%d | Writing section:"
- " marker:0x%x size:%d",
- offset, cur_marker, cur->size);
+ "offset: %zu | Writing section:"
+ " marker:0x%x size: %d",
+ offset, (unsigned)cur_marker, cur->size);
bytes_wrote = fwrite(tmp_buf, 1, bytes_to_write, m_out_file);
offset += bytes_wrote;
@@ -637,11 +638,11 @@ PlatformResult JpegFile::saveToFilePriv(const std::string& out_path) {
if (bytes_wrote != bytes_to_write) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Could not write JPEG file",
- ("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write, bytes_wrote));
+ ("Couldn't wrote %zu bytes! Only %zu bytes wrote", bytes_to_write, bytes_wrote));
}
if (write_section_data && cur->size > 0) {
- LoggerD("offset:%d | Writing data with length:%d", offset, cur->size);
+ LoggerD("offset: %zu | Writing data with length: %d", offset, cur->size);
bytes_to_write = cur->size;
bytes_wrote = fwrite(cur->data_ptr, 1, bytes_to_write, m_out_file);
@@ -650,12 +651,12 @@ PlatformResult JpegFile::saveToFilePriv(const std::string& out_path) {
if (bytes_wrote != bytes_to_write) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Could not write JPEG file",
- ("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write, bytes_wrote));
+ ("Couldn't wrote %zu bytes! Only %zu bytes wrote", bytes_to_write, bytes_wrote));
}
}
if (write_exif_data && exif_output_data && exif_output_size > 0) {
- LoggerD("offset:%d | Writing new exif data with length:%d", offset, exif_output_size);
+ LoggerD("offset: %zu | Writing new exif data with length: %u", offset, exif_output_size);
bytes_to_write = exif_output_size;
bytes_wrote = fwrite(exif_output_data.get(), 1, bytes_to_write, m_out_file);
@@ -664,12 +665,12 @@ PlatformResult JpegFile::saveToFilePriv(const std::string& out_path) {
if (bytes_wrote != bytes_to_write) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Could not write JPEG file",
- ("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write, bytes_wrote));
+ ("Couldn't wrote %zu bytes! Only %zu bytes wrote", bytes_to_write, bytes_wrote));
}
}
if (JPEG_MARKER_SOS == cur_marker) {
- LoggerD("offset:%d | Writing image data stream with lenght:%d", offset, m_image_size);
+ LoggerD("offset: %zu | Writing image data stream with lenght: %zu", offset, m_image_size);
bytes_to_write = m_image_size;
bytes_wrote = fwrite(m_image_data, 1, bytes_to_write, m_out_file);
@@ -678,19 +679,19 @@ PlatformResult JpegFile::saveToFilePriv(const std::string& out_path) {
if (bytes_wrote != bytes_to_write) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Could not write JPEG file",
- ("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write, bytes_wrote));
+ ("Couldn't wrote %zu bytes! Only %zu bytes wrote", bytes_to_write, bytes_wrote));
}
}
}
if (m_padding_data && m_padding_data_size > 0) {
- LoggerD("Padding data exists and contains:%d bytes saving to JPEG file", m_padding_data_size);
+ LoggerD("Padding data exists and contains: %zu bytes saving to JPEG file", m_padding_data_size);
const std::size_t bytes_wrote = fwrite(m_image_data, 1, m_padding_data_size, m_out_file);
if (bytes_wrote != m_padding_data_size) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Could not write JPEG file",
- ("Couldn't wrote %d bytes! Only %d bytes wrote", m_padding_data_size, bytes_wrote));
+ ("Couldn't wrote %zu bytes! Only %zu bytes wrote", m_padding_data_size, bytes_wrote));
}
}
@@ -724,7 +725,7 @@ JpegFileSectionPtr JpegFile::getExifSection() {
first_exif_section = cur;
} else {
LoggerW(
- "Warning: found %d APP1/Exif sections -"
+ "Warning: found %zu APP1/Exif sections -"
" only first is currently supported!",
num_exif_sections);
}
diff --git a/src/feedback/feedback_api.js b/src/feedback/feedback_api.js
index 8863c317..378d91ca 100755
--- a/src/feedback/feedback_api.js
+++ b/src/feedback/feedback_api.js
@@ -20,57 +20,9 @@ var types_ = validator_.Types;
var type_ = xwalk.utils.type;
var native_ = new xwalk.utils.NativeManager(extension);
-var ExceptionMap = {
- UnknownError: WebAPIException.UNKNOWN_ERR,
- TypeMismatchError: WebAPIException.TYPE_MISMATCH_ERR,
- InvalidValuesError: WebAPIException.INVALID_VALUES_ERR,
- IOError: WebAPIException.IO_ERR,
- ServiceNotAvailableError: WebAPIException.SERVICE_NOT_AVAILABLE_ERR,
- SecurityError: WebAPIException.SECURITY_ERR,
- NetworkError: WebAPIException.NETWORK_ERR,
- NotSupportedError: WebAPIException.NOT_SUPPORTED_ERR,
- NotFoundError: WebAPIException.NOT_FOUND_ERR,
- InvalidAccessError: WebAPIException.INVALID_ACCESS_ERR,
- AbortError: WebAPIException.ABORT_ERR,
- QuotaExceededError: WebAPIException.QUOTA_EXCEEDED_ERR
-};
-
-function callNative(cmd, args) {
- var json = { cmd: cmd, args: args };
- var argjson = JSON_.stringify(json);
- var resultString = extension.internal.sendSyncMessage(argjson);
- var result = JSON_.parse(resultString);
-
- if (typeof result !== 'object') {
- throw new WebAPIException(WebAPIException.UNKNOWN_ERR);
- }
-
- if (result['status'] == 'success') {
- if (result.hasOwnProperty('result')) {
- return result['result'];
- }
- return true;
- } else if (result['status'] == 'error') {
- var err = result['error'];
- if (err) {
- if (ExceptionMap[err.name]) {
- throw new WebAPIException(ExceptionMap[err.name], err.message);
- } else {
- throw new WebAPIException(WebAPIException.UNKNOWN_ERR, err.message);
- }
- }
- return false;
- }
-}
-
-function SetReadOnlyProperty(obj, n, v) {
- Object.defineProperty(obj, n, { value: v, writable: false });
-}
-
var FeedbackType = {
TYPE_SOUND: 'TYPE_SOUND',
- TYPE_VIBRATION: 'TYPE_VIBRATION',
- NONE: 'NONE'
+ TYPE_VIBRATION: 'TYPE_VIBRATION'
};
var FeedbackPattern = {
@@ -124,7 +76,12 @@ FeedbackManager.prototype.isPatternSupported = function(pattern, type) {
{ name: 'pattern', type: types_.ENUM, values: Object.keys(FeedbackPattern) },
{ name: 'type', type: types_.ENUM, values: Object.keys(FeedbackType) }
]);
- return callNative('FeedbackManager_isPatternSupported', args);
+
+ var result = native_.callSync('FeedbackManager_isPatternSupported', args);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+ return native_.getResultObject(result);
};
FeedbackManager.prototype.play = function(pattern, type) {
@@ -148,15 +105,19 @@ FeedbackManager.prototype.play = function(pattern, type) {
type: args.type ? args.type : 'any'
};
- callNative('FeedbackManager_play', nativeParam);
- return;
+ var result = native_.callSync('FeedbackManager_play', nativeParam);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
};
FeedbackManager.prototype.stop = function() {
var args = validator_.validateArgs(arguments, []);
- callNative('FeedbackManager_stop', args);
- return;
+ var result = native_.callSync('FeedbackManager_stop', args);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
};
exports = new FeedbackManager();
diff --git a/src/feedback/feedback_manager.cc b/src/feedback/feedback_manager.cc
index 3aba534a..07e03710 100644
--- a/src/feedback/feedback_manager.cc
+++ b/src/feedback/feedback_manager.cc
@@ -137,9 +137,11 @@ common::PlatformResult FeedbackManager::isPatternSupported(const std::string &pa
}
int ret = feedback_is_supported_pattern(type_e, pattern_e, patternStatus);
- if (ret != FEEDBACK_ERROR_NONE) {
+ if (FEEDBACK_ERROR_NOT_SUPPORTED == ret) {
+ *patternStatus = false;
+ } else if (FEEDBACK_ERROR_NONE != ret) {
LoggerE("isPatternSupported failed: %d", ret);
- return CodeToResult(FEEDBACK_ERROR_NOT_SUPPORTED, "Pattern not supported");
+ return CodeToResult(ret, "Checking pattern support failed");
}
m_feedbackMapsPtr->setPatternSupport(pattern_e, type_e, *patternStatus);
diff --git a/src/filesystem/filesystem_api.js b/src/filesystem/filesystem_api.js
index cd2442ce..38a9b269 100755
--- a/src/filesystem/filesystem_api.js
+++ b/src/filesystem/filesystem_api.js
@@ -18,4 +18,5 @@
//= require('common.js');
//= require('file_stream.js');
//= require('file.js');
+//= require('file_handle.js');
//= require('file_system_manager.js');
diff --git a/src/filesystem/filesystem_instance.cc b/src/filesystem/filesystem_instance.cc
index 5df0cbbe..06d8095d 100644
--- a/src/filesystem/filesystem_instance.cc
+++ b/src/filesystem/filesystem_instance.cc
@@ -16,11 +16,13 @@
#include "filesystem/filesystem_instance.h"
+#include <linux/limits.h>
#include <cstdint>
#include <functional>
#include <stdexcept>
#include <sys/stat.h>
+#include <system_error>
#include "common/logger.h"
#include "common/picojson.h"
#include "common/platform_exception.h"
@@ -33,20 +35,76 @@ namespace extension {
namespace filesystem {
namespace {
+
+using common::tools::GetErrorString;
+
// The privileges that required in Filesystem API
const std::string kPrivilegeFilesystemRead = "http://tizen.org/privilege/filesystem.read";
const std::string kPrivilegeFilesystemWrite = "http://tizen.org/privilege/filesystem.write";
+
+const std::string kISOEncoding = "ISO-8859-1";
+const std::string kUTF8Encoding = "UTF-8";
+
+std::string GetFopenMode(const picojson::value& args) {
+ ScopeLogger();
+ const std::string& open_mode = args.get("openMode").get<std::string>();
+
+ if ("rw" == open_mode) {
+ return "r+";
+ } else if ("rwo" == open_mode) {
+ return "w+";
+ }
+
+ return open_mode;
+}
+
+bool WriteAccessRequested(const picojson::value& args) {
+ ScopeLogger();
+ const std::string& open_mode = args.get("openMode").get<std::string>();
+
+ return "a" == open_mode || "rw" == open_mode || "rwo" == open_mode || "w" == open_mode;
+}
+
+bool ReadAccessRequested(const picojson::value& args) {
+ ScopeLogger();
+ const std::string& open_mode = args.get("openMode").get<std::string>();
+
+ return "r" == open_mode || "rw" == open_mode || "rwo" == open_mode;
+}
+
+bool ShouldMakeParents(const picojson::value& args) {
+ ScopeLogger();
+ const std::string& path = args.get("path").get<std::string>();
+ struct stat buf {};
+ if (FilesystemUtils::CheckIfExists(FilesystemUtils::Dirname(path), &buf)) {
+ return false;
+ }
+ bool make_parents = args.get("makeParents").get<bool>();
+ const std::string& open_mode = args.get("openMode").get<std::string>();
+ return make_parents && ("w" == open_mode || "a" == open_mode || "rwo" == open_mode);
+}
}
using namespace common;
using namespace extension::filesystem;
+using namespace std::string_literals;
+
+FileHandle::~FileHandle() {
+ ScopeLogger();
+
+ if (file_handle && std::fclose(file_handle)) {
+ LoggerE("close file failed, error message: %s", GetErrorString(errno).c_str());
+ }
+}
FilesystemInstance::FilesystemInstance() {
ScopeLogger();
+
using std::placeholders::_1;
using std::placeholders::_2;
#define REGISTER_SYNC(c, x) RegisterSyncHandler(c, std::bind(&FilesystemInstance::x, this, _1, _2));
+
REGISTER_SYNC("File_stat", FileStat);
REGISTER_SYNC("File_statSync", FileStatSync);
REGISTER_SYNC("File_createSync", FileCreateSync);
@@ -67,12 +125,38 @@ FilesystemInstance::FilesystemInstance() {
REGISTER_SYNC("File_removeDirectory", RemoveDirectory);
REGISTER_SYNC("File_copyTo", CopyTo);
REGISTER_SYNC("FileSystemManager_getCanonicalPath", FileSystemManagerGetCanonicalPath);
+
+ REGISTER_SYNC("FileSystemManager_openFile", FileSystemManagerOpenFile);
+ REGISTER_SYNC("FileSystemManager_createDirectory", FileSystemManagerCreateDirectory);
+ REGISTER_SYNC("FileSystemManager_deleteFile", FileSystemManagerDeleteFile);
+ REGISTER_SYNC("FileSystemManager_deleteDirectory", FileSystemManagerDeleteDirectory);
+ REGISTER_SYNC("FileSystemManager_copyFile", FileSystemManagerCopyFile);
+ REGISTER_SYNC("FileSystemManager_copyDirectory", FileSystemManagerCopyDirectory);
+ REGISTER_SYNC("FileSystemManager_moveFile", FileSystemManagerMoveFile);
+ REGISTER_SYNC("FileSystemManager_moveDirectory", FileSystemManagerMoveDirectory);
+ REGISTER_SYNC("FileSystemManager_rename", FileSystemManagerRename);
+ REGISTER_SYNC("FileSystemManager_listDirectory", FileSystemManagerListDirectory);
+ REGISTER_SYNC("FileSystemManager_isFile", FileSystemManagerIsFile);
+ REGISTER_SYNC("FileSystemManager_isDirectory", FileSystemManagerIsDirectory);
+ REGISTER_SYNC("FileSystemManager_pathExists", FileSystemManagerPathExists);
+ REGISTER_SYNC("FileSystemManager_getLimits", FileSystemManagerGetLimits);
+
+ REGISTER_SYNC("FileHandle_seek", FileHandleSeek);
+ REGISTER_SYNC("FileHandle_readString", FileHandleReadString);
+ REGISTER_SYNC("FileHandle_writeString", FileHandleWriteString);
+ REGISTER_SYNC("FileHandle_readData", FileHandleReadData);
+ REGISTER_SYNC("FileHandle_writeData", FileHandleWriteData);
+ REGISTER_SYNC("FileHandle_flush", FileHandleFlush);
+ REGISTER_SYNC("FileHandle_sync", FileHandleSync);
+ REGISTER_SYNC("FileHandle_close", FileHandleClose);
+
#undef REGISTER_SYNC
FilesystemManager::GetInstance().AddListener(this);
}
FilesystemInstance::~FilesystemInstance() {
ScopeLogger();
+ worker.stop();
FilesystemManager::GetInstance().StopListening();
FilesystemManager::GetInstance().RemoveListener();
}
@@ -85,10 +169,14 @@ FilesystemInstance::~FilesystemInstance() {
void FilesystemInstance::FileCreateSync(const picojson::value& args, picojson::object& out) {
ScopeLogger();
+ LoggerW(
+ "DEPRECATION WARNING: File.createFile() is deprecated since Tizen 5.0. Use "
+ "FileSystemManager.openFile() instead.");
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
CHECK_EXIST(args, "location", out)
-
const std::string& location = args.get("location").get<std::string>();
+ CHECK_STORAGE_ACCESS(location, &out);
auto onSuccess = [&](const FilesystemStat& data) {
ScopeLogger("Entered into asynchronous function, onSuccess");
@@ -105,14 +193,21 @@ void FilesystemInstance::FileCreateSync(const picojson::value& args, picojson::o
void FilesystemInstance::FileRename(const picojson::value& args, picojson::object& out) {
ScopeLogger();
+ LoggerW(
+ "DEPRECATION WARNING: File.moveTo() is deprecated since Tizen 5.0. Use "
+ "FileSystemManager.moveFile() or FileSystemManager.moveDirectory() instead.");
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
CHECK_EXIST(args, "callbackId", out)
+
CHECK_EXIST(args, "oldPath", out)
+ const std::string& oldPath = args.get("oldPath").get<std::string>();
+ CHECK_STORAGE_ACCESS(oldPath, &out);
CHECK_EXIST(args, "newPath", out)
+ const std::string& newPath = args.get("newPath").get<std::string>();
+ CHECK_STORAGE_ACCESS(newPath, &out);
double callback_id = args.get("callbackId").get<double>();
- const std::string& oldPath = args.get("oldPath").get<std::string>();
- const std::string& newPath = args.get("newPath").get<std::string>();
auto onSuccess = [this, callback_id](const FilesystemStat& data) {
ScopeLogger("Entered into asynchronous function, onSuccess");
@@ -133,7 +228,7 @@ void FilesystemInstance::FileRename(const picojson::value& args, picojson::objec
};
FilesystemManager& fsm = FilesystemManager::GetInstance();
- common::TaskQueue::GetInstance().Async(
+ common::TaskQueue::GetInstance().Queue(
std::bind(&FilesystemManager::Rename, &fsm, oldPath, newPath, onSuccess, onError));
}
@@ -182,17 +277,54 @@ static auto from_utf8 = &decode_binary_from_string;
}
static constexpr std::size_t NPOS = (std::size_t)(-1);
+
+/**
+ * On failure throws std::system_error
+ */
+static std::size_t file_size(FILE* file) {
+ ScopeLogger();
+
+ struct ::stat buf;
+ int status = ::fstat(::fileno(file), &buf);
+ if (status != 0) {
+ throw std::system_error{errno, std::generic_category(), "failed to get file size"};
+ }
+
+ return buf.st_size;
+}
+
+/**
+ * Returns the amount of bytes to the EOF starting from current file-position indicator.
+ *
+ * On failure throws std::system_error
+ */
+static std::size_t file_bytes_to_eof(FILE* file) {
+ ScopeLogger();
+
+ std::size_t total_fize_size = file_size(file);
+ long file_position = ftell(file);
+ if (-1 == file_position) {
+ throw std::system_error{errno, std::generic_category(),
+ "Failed to get file position"s + GetErrorString(errno)};
+ }
+ return total_fize_size - static_cast<size_t>(file_position);
+}
+
+static std::vector<std::uint8_t> read_file(FILE* file, std::size_t length = NPOS,
+ std::size_t* read_bytes = nullptr);
+
/**
* Returns a buffer. If length is NPOS, then it reads whole file, up to the end.
* On failure throws std::runtime_error
*/
-static std::vector<std::uint8_t> read_file(std::string path, std::size_t offset,
+static std::vector<std::uint8_t> read_file(std::string path, long offset = 0,
std::size_t length = NPOS) {
ScopeLogger();
FILE* file = std::fopen(path.c_str(), "r");
if (!file) {
- throw std::runtime_error("cannot open file to read");
+ std::string err_msg = std::string("Cannot open file to read. ") + GetErrorString(errno);
+ throw std::system_error{errno, std::generic_category(), err_msg};
}
SCOPE_EXIT {
@@ -202,27 +334,45 @@ static std::vector<std::uint8_t> read_file(std::string path, std::size_t offset,
}
};
- if (std::fseek(file, offset, SEEK_SET) != 0) {
- throw std::runtime_error("cannot perform seek");
+ if (0 != offset && 0 != std::fseek(file, offset, SEEK_SET)) {
+ std::string err_msg = std::string("Cannot perform seek. ") + GetErrorString(errno);
+ throw std::system_error{errno, std::generic_category(), err_msg};
+ }
+
+ if (NPOS == length) {
+ length = file_size(file) - offset;
}
+ return read_file(file, length);
+}
+
+/**
+ * Returns a buffer. If length is NPOS, then it reads whole file, up to the end.
+ * On failure throws std::runtime_error
+ */
+static std::vector<std::uint8_t> read_file(FILE* file, std::size_t length /*= NPOS*/,
+ std::size_t* read_bytes /* = nullptr*/) {
+ ScopeLogger();
+
// By default reads whole file. Get the file size.
- if (length == NPOS) {
- struct ::stat buf;
- if (::fstat(::fileno(file), &buf) != 0) {
- throw std::runtime_error("cannot fstat");
- }
- length = buf.st_size - offset;
+ if (NPOS == length) {
+ length = file_size(file);
}
- std::vector<std::uint8_t> out_buf(length);
+ std::vector<std::uint8_t> out_buf;
+ try {
+ out_buf.resize(length);
+ } catch (std::bad_alloc& err) {
+ throw std::runtime_error{"Could not allocate memory"};
+ }
std::uint8_t* data_p = out_buf.data();
std::uint8_t* end_p = data_p + length;
while (data_p != end_p) {
data_p += std::fread(data_p, 1, end_p - data_p, file);
if (std::ferror(file)) {
- throw std::runtime_error("error during file read");
+ std::string err_msg = std::string("Error during file read. ") + GetErrorString(errno);
+ throw std::runtime_error(err_msg);
}
if (std::feof(file)) {
@@ -230,20 +380,52 @@ static std::vector<std::uint8_t> read_file(std::string path, std::size_t offset,
break;
}
}
+ // read_file function is used in API since version 1.0.
+ // read_bytes was added in Tizen 5.0, with default value equal to nullptr, the behaviour is not
+ // changed.
+ // It is used to return the actual number of read bytes, because requested length might be bigger
+ // than possible bytes to be read.
+ if (nullptr != read_bytes) {
+ *read_bytes = std::distance(out_buf.data(), data_p);
+ }
return out_buf;
}
/**
* On failure throws std::runtime_error
*/
-void write_file(const std::uint8_t* data, std::size_t len, std::string path, std::size_t offset,
- bool rewrite) {
+void write_file(const std::uint8_t* data, std::size_t len, FILE* file) {
ScopeLogger();
- FILE* file = fopen(path.c_str(), rewrite ? "w" : "r+");
+ const std::uint8_t* data_p = data;
+ const std::uint8_t* end_p = data + len;
+ while (data_p != end_p) {
+ data_p += fwrite(data_p, 1, end_p - data_p, file);
+
+ if (std::ferror(file)) {
+ std::string err_msg = std::string("Error during file write. ") + GetErrorString(errno);
+ throw std::runtime_error(err_msg);
+ }
+ }
+
+ if (std::fflush(file)) {
+ std::string err_msg = std::string("Error during file write. ") + GetErrorString(errno);
+ throw std::runtime_error(err_msg);
+ }
+}
+
+/**
+ * On failure throws std::runtime_error
+ */
+void write_file(const std::uint8_t* data, std::size_t len, std::string path, long offset,
+ const char* mode) {
+ ScopeLogger();
+
+ FILE* file = std::fopen(path.c_str(), mode);
if (!file) {
- throw std::runtime_error("cannot open file to write");
+ std::string err_msg = std::string("Cannot open file to write. ") + GetErrorString(errno);
+ throw std::runtime_error(err_msg);
}
SCOPE_EXIT {
@@ -253,23 +435,167 @@ void write_file(const std::uint8_t* data, std::size_t len, std::string path, std
}
};
- if (std::fseek(file, offset, SEEK_SET) != 0) {
- throw std::runtime_error("cannot perform seek");
+ if (offset != 0 && std::fseek(file, offset, SEEK_SET) != 0) {
+ std::string err_msg = std::string("Cannot perform seek. ") + GetErrorString(errno);
+ throw std::system_error{errno, std::generic_category(), err_msg};
}
- const std::uint8_t* data_p = data;
- const std::uint8_t* end_p = data + len;
- while (data_p != end_p) {
- data_p += fwrite(data_p, 1, end_p - data_p, file);
+ write_file(data, len, file);
+}
- if (std::ferror(file)) {
- throw std::runtime_error("error during file write");
+#define FIRST_BIT_MASK 0x80
+#define SECOND_BIT_MASK 0x40
+#define THIRD_BIT_MASK 0x20
+#define FOURTH_BIT_MASK 0x10
+#define FIFTH_BIT_MASK 0x08
+
+enum class ByteOfUTF8Classification {
+ NOT_VALID,
+ ONE_BYTE_CHAR,
+ FIRST_OF_2_BYTES,
+ FIRST_OF_3_BYTES,
+ FIRST_OF_4_BYTES,
+ EXTENSION_BYTE
+};
+
+ByteOfUTF8Classification is_utf8_byte(uint8_t byte) {
+ if (FIRST_BIT_MASK & byte) {
+ if (SECOND_BIT_MASK & byte) {
+ if (THIRD_BIT_MASK & byte) {
+ if (FOURTH_BIT_MASK & byte) {
+ if (FIFTH_BIT_MASK & byte) {
+ return ByteOfUTF8Classification::NOT_VALID;
+ } else {
+ return ByteOfUTF8Classification::FIRST_OF_4_BYTES;
+ }
+ } else {
+ return ByteOfUTF8Classification::FIRST_OF_3_BYTES;
+ }
+ } else {
+ return ByteOfUTF8Classification::FIRST_OF_2_BYTES;
+ }
+ } else {
+ return ByteOfUTF8Classification::EXTENSION_BYTE;
+ }
+ } else {
+ return ByteOfUTF8Classification::ONE_BYTE_CHAR;
+ }
+}
+
+void skip_partial_character(std::vector<std::uint8_t>& buf) {
+ auto buf_position = buf.begin();
+
+ while (buf.end() != buf_position &&
+ (ByteOfUTF8Classification::EXTENSION_BYTE == is_utf8_byte(*buf_position))) {
+ buf_position = buf.erase(buf_position);
+ LoggerD("Removed UTF-8 Extension Byte from begining of read buffer");
+ }
+}
+
+bool validate_and_check_character_count(std::vector<std::uint8_t>& buf, unsigned long& char_count,
+ short& no_of_extensions_expected) {
+ ScopeLogger();
+ char_count = 0;
+ no_of_extensions_expected = 0;
+ auto buf_position = buf.begin();
+
+ skip_partial_character(buf);
+
+ while (buf.end() != buf_position) {
+ switch (is_utf8_byte(*buf_position)) {
+ case ByteOfUTF8Classification::EXTENSION_BYTE:
+ no_of_extensions_expected--;
+ if (0 > no_of_extensions_expected) {
+ return false;
+ } else if (0 == no_of_extensions_expected) {
+ char_count++;
+ }
+ break;
+ case ByteOfUTF8Classification::ONE_BYTE_CHAR:
+ if (0 != no_of_extensions_expected) {
+ return false;
+ }
+ char_count++;
+ break;
+ case ByteOfUTF8Classification::FIRST_OF_2_BYTES:
+ if (0 != no_of_extensions_expected) {
+ return false;
+ }
+ no_of_extensions_expected = 1;
+ break;
+ case ByteOfUTF8Classification::FIRST_OF_3_BYTES:
+ if (0 != no_of_extensions_expected) {
+ return false;
+ }
+ no_of_extensions_expected = 2;
+ break;
+ case ByteOfUTF8Classification::FIRST_OF_4_BYTES:
+ if (0 != no_of_extensions_expected) {
+ return false;
+ }
+ no_of_extensions_expected = 3;
+ break;
+ case ByteOfUTF8Classification::NOT_VALID:
+ return false;
+ default:
+ LoggerE("Abnormal value returned from is_utf8_byte function");
}
+ buf_position++;
}
+ return true;
+}
- if (std::fflush(file)) {
- throw std::runtime_error("error during file write");
+/*
+ * add_utf8_chars_to_buffer
+ * Method returns false if byte read is not a valid utf8 char
+ */
+bool add_utf8_chars_to_buffer(FILE* file, std::vector<std::uint8_t>& buf, int chars_to_read,
+ short& extension_bytes_expected) {
+ int character;
+ LoggerD("chars_to_read: %i", chars_to_read);
+ LoggerD("extension_bytes_expected: %i", extension_bytes_expected);
+ while (chars_to_read) {
+ if (extension_bytes_expected) {
+ character = getc(file);
+ if (EOF == character) {
+ return false;
+ }
+ buf.push_back(character);
+ if (!--extension_bytes_expected) {
+ chars_to_read--;
+ }
+ continue;
+ }
+ character = getc(file);
+ if (EOF == character) {
+ return false;
+ }
+ buf.push_back(character);
+ switch (is_utf8_byte(character)) {
+ case ByteOfUTF8Classification::ONE_BYTE_CHAR:
+ chars_to_read--;
+ break;
+ case ByteOfUTF8Classification::FIRST_OF_2_BYTES:
+ extension_bytes_expected = 1;
+ break;
+ case ByteOfUTF8Classification::FIRST_OF_3_BYTES:
+ extension_bytes_expected = 2;
+ break;
+ case ByteOfUTF8Classification::FIRST_OF_4_BYTES:
+ extension_bytes_expected = 3;
+ break;
+ case ByteOfUTF8Classification::EXTENSION_BYTE:
+ LoggerD("unexpected EXTENSION_BYTE");
+ return false;
+ case ByteOfUTF8Classification::NOT_VALID:
+ LoggerE("unexpected NOT_VALID byte while reading utf-8");
+ return false;
+ default:
+ LoggerE("Abnormal. Last read char: %c: ", character);
+ return false;
+ }
}
+ return true;
}
namespace base64 {
@@ -339,6 +665,10 @@ static std::vector<std::uint8_t> decode(const char* str, std::size_t len) {
void FilesystemInstance::FileReadString(const picojson::value& args, picojson::object& out) {
ScopeLogger();
+ LoggerW(
+ "DEPRECATION WARNING: This method is deprecated since Tizen 5.0.Use FileHandle.readString() "
+ "or FileHandle.readStringNonBlocking() instead.");
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
CHECK_EXIST(args, "location", out)
CHECK_EXIST(args, "offset", out)
@@ -369,6 +699,10 @@ void FilesystemInstance::FileReadString(const picojson::value& args, picojson::o
void FilesystemInstance::FileReadBytes(const picojson::value& args, picojson::object& out) {
ScopeLogger();
+ LoggerW(
+ "DEPRECATION WARNING: This method is deprecated since Tizen 5.0. Use FileHandle.readData() "
+ "or FileHandle.readDataNonBlocking() instead.");
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
CHECK_EXIST(args, "location", out)
CHECK_EXIST(args, "offset", out)
@@ -392,16 +726,21 @@ void FilesystemInstance::FileReadBytes(const picojson::value& args, picojson::ob
void FilesystemInstance::FileWriteString(const picojson::value& args, picojson::object& out) {
ScopeLogger();
+ LoggerW(
+ "DEPRECATION WARNING: FileStream.write() is deprecated since Tizen 5.0. Use "
+ "FileHandle.writeString() or FileHandle.writeStringNonBlocking() instead.");
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
CHECK_EXIST(args, "location", out)
CHECK_EXIST(args, "data", out)
CHECK_EXIST(args, "offset", out)
- CHECK_EXIST(args, "rewrite", out)
+ CHECK_EXIST(args, "truncate", out)
const std::string& location = args.get("location").get<std::string>();
const std::string& str = args.get("data").get<std::string>();
size_t offset = static_cast<size_t>(args.get("offset").get<double>());
- bool rewrite = static_cast<bool>(args.get("rewrite").get<bool>());
+ bool truncate = static_cast<bool>(args.get("truncate").get<bool>());
+ const char* mode = truncate ? "w" : "r+";
const std::string& encoding =
args.contains("encoding") ? args.get("encoding").get<std::string>() : "utf-8";
@@ -409,11 +748,11 @@ void FilesystemInstance::FileWriteString(const picojson::value& args, picojson::
if (encoding == "iso-8859-1") {
std::vector<std::uint8_t> data;
latin1::from_utf8(str, data);
- write_file(data.data(), data.size(), location, offset, rewrite);
+ write_file(data.data(), data.size(), location, offset, mode);
} else { // default: UTF-8
const std::uint8_t* buf = (const std::uint8_t*)str.c_str();
std::size_t len = str.length();
- write_file(buf, len, location, offset, rewrite);
+ write_file(buf, len, location, offset, mode);
}
} catch (std::runtime_error& e) {
LoggerE("Cannot write to file %s, cause: %s", location.c_str(), e.what());
@@ -426,21 +765,26 @@ void FilesystemInstance::FileWriteString(const picojson::value& args, picojson::
void FilesystemInstance::FileWriteBytes(const picojson::value& args, picojson::object& out) {
ScopeLogger();
+ LoggerW(
+ "DEPRECATION WARNING: FileStream.writeBytes() is deprecated since Tizen 5.0. To read and Use "
+ "FileHandle.writeData() or FileHandle.writeDataNonBlocking() instead.");
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
CHECK_EXIST(args, "location", out)
CHECK_EXIST(args, "data", out)
CHECK_EXIST(args, "offset", out)
- CHECK_EXIST(args, "rewrite", out)
+ CHECK_EXIST(args, "truncate", out)
const std::string& location = args.get("location").get<std::string>();
const std::string& str = args.get("data").get<std::string>();
size_t offset = static_cast<size_t>(args.get("offset").get<double>());
- bool rewrite = static_cast<bool>(args.get("rewrite").get<bool>());
+ bool truncate = static_cast<bool>(args.get("truncate").get<bool>());
+ const char* mode = truncate ? "w" : "r+";
try {
std::vector<std::uint8_t> data;
decode_binary_from_string(str, data);
- write_file(data.data(), data.size(), location, offset, rewrite);
+ write_file(data.data(), data.size(), location, offset, mode);
} catch (std::runtime_error& e) {
LoggerE("Cannot write to %s, cause: %s", location.c_str(), e.what());
PrepareError(FilesystemError::Other, out);
@@ -452,16 +796,22 @@ void FilesystemInstance::FileWriteBytes(const picojson::value& args, picojson::o
void FilesystemInstance::FileWriteBase64(const picojson::value& args, picojson::object& out) {
ScopeLogger();
+ LoggerW(
+ "DEPRECATION WARNING: FileStream.writeBase64() is deprecated since Tizen 5.0. Use "
+ "FileHandle.writeData() or FileHandle.writeDataNonBlocking() in combination with atob() and "
+ "btoa() functions instead.");
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
CHECK_EXIST(args, "location", out)
CHECK_EXIST(args, "data", out)
CHECK_EXIST(args, "offset", out)
- CHECK_EXIST(args, "rewrite", out)
+ CHECK_EXIST(args, "truncate", out)
const std::string& location = args.get("location").get<std::string>();
const std::string& str = args.get("data").get<std::string>();
size_t offset = static_cast<size_t>(args.get("offset").get<double>());
- bool rewrite = static_cast<bool>(args.get("rewrite").get<bool>());
+ bool truncate = static_cast<bool>(args.get("truncate").get<bool>());
+ const char* mode = truncate ? "w" : "r+";
std::vector<std::uint8_t> data;
try {
@@ -473,7 +823,7 @@ void FilesystemInstance::FileWriteBase64(const picojson::value& args, picojson::
}
try {
- write_file(data.data(), data.size(), location, offset, rewrite);
+ write_file(data.data(), data.size(), location, offset, mode);
ReportSuccess(picojson::value{(double)data.size()}, out);
} catch (std::runtime_error& e) {
LoggerE("Cannot write to %s, cause: %s", location.c_str(), e.what());
@@ -484,11 +834,12 @@ void FilesystemInstance::FileWriteBase64(const picojson::value& args, picojson::
void FilesystemInstance::FileStat(const picojson::value& args, picojson::object& out) {
ScopeLogger();
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
- CHECK_EXIST(args, "callbackId", out)
CHECK_EXIST(args, "location", out)
+ const std::string& location = args.get("location").get<std::string>();
+ CHECK_STORAGE_ACCESS(location, &out);
+ CHECK_EXIST(args, "callbackId", out)
double callback_id = args.get("callbackId").get<double>();
- const std::string& location = args.get("location").get<std::string>();
auto onSuccess = [this, callback_id](const FilesystemStat& data) {
ScopeLogger("Entered into asynchronous function, onSuccess");
@@ -517,8 +868,8 @@ void FilesystemInstance::FileStatSync(const picojson::value& args, picojson::obj
ScopeLogger();
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
CHECK_EXIST(args, "location", out)
-
const std::string& location = args.get("location").get<std::string>();
+ CHECK_STORAGE_ACCESS(location, &out);
auto onSuccess = [&](const FilesystemStat& data) {
ScopeLogger("Entered into asynchronous function, onSuccess");
@@ -643,10 +994,14 @@ void FilesystemInstance::FileSystemManagerMakeDirectory(const picojson::value& a
void FilesystemInstance::FileSystemManagerMakeDirectorySync(const picojson::value& args,
picojson::object& out) {
ScopeLogger();
+ LoggerW(
+ "DEPRECATION WARNING: File.createDirectory() is deprecated since Tizen 5.0. Use "
+ "FileSystemManager.createDirectory() instead.");
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
CHECK_EXIST(args, "location", out)
-
const std::string& location = args.get("location").get<std::string>();
+ CHECK_STORAGE_ACCESS(location, &out);
auto onResult = [&](FilesystemError e) {
ScopeLogger("Entered into asynchronous function, onResult");
@@ -661,6 +1016,10 @@ void FilesystemInstance::FileSystemManagerMakeDirectorySync(const picojson::valu
void FilesystemInstance::ReadDir(const picojson::value& args, picojson::object& out) {
ScopeLogger();
+ LoggerW(
+ "DEPRECATION WARNING: File.listFiles() is deprecated since Tizen 5.0. Use "
+ "FileSystemManager.listDirectory() instead.");
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
CHECK_EXIST(args, "pathToDir", out)
CHECK_EXIST(args, "callbackId", out)
@@ -706,11 +1065,15 @@ void FilesystemInstance::ReadDir(const picojson::value& args, picojson::object&
void FilesystemInstance::UnlinkFile(const picojson::value& args, picojson::object& out) {
ScopeLogger();
+ LoggerW(
+ "DEPRECATION WARNING: File.deleteFile() is deprecated since Tizen 5.0. Use "
+ "FileSystemManager.deleteFile() instead.");
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
CHECK_EXIST(args, "pathToFile", out)
-
double callback_id = args.get("callbackId").get<double>();
const std::string& pathToFile = args.get("pathToFile").get<std::string>();
+ CHECK_STORAGE_ACCESS(pathToFile, &out);
auto onSuccess = [this, callback_id]() {
ScopeLogger("Entered into asynchronous function, onSuccess");
@@ -738,11 +1101,15 @@ void FilesystemInstance::UnlinkFile(const picojson::value& args, picojson::objec
void FilesystemInstance::RemoveDirectory(const picojson::value& args, picojson::object& out) {
ScopeLogger();
+ LoggerW(
+ "DEPRECATION WARNING: File.deleteDirectory() is deprecated since Tizen 5.0. Use "
+ "FileSystemManager.deleteDirectory() instead.");
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
CHECK_EXIST(args, "pathToDelete", out)
-
double callback_id = args.get("callbackId").get<double>();
const std::string& pathToDelete = args.get("pathToDelete").get<std::string>();
+ CHECK_STORAGE_ACCESS(pathToDelete, &out);
auto onSuccess = [this, callback_id]() {
ScopeLogger("Entered into asynchronous function, onSuccess");
@@ -764,21 +1131,29 @@ void FilesystemInstance::RemoveDirectory(const picojson::value& args, picojson::
};
FilesystemManager& fm = FilesystemManager::GetInstance();
- common::TaskQueue::GetInstance().Async(
+ common::TaskQueue::GetInstance().Queue(
std::bind(&FilesystemManager::RemoveDirectory, &fm, pathToDelete, onSuccess, onError));
}
void FilesystemInstance::CopyTo(const picojson::value& args, picojson::object& out) {
ScopeLogger();
+ LoggerW(
+ "DEPRECATION WARNING: File.copyTo() is deprecated since Tizen 5.0. Use "
+ "FileSystemManager.CopyFile() or FileSystemManager.CopyDirectory() instead.");
+
CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
CHECK_EXIST(args, "callbackId", out)
+
CHECK_EXIST(args, "originFilePath", out)
+ const std::string& originPath = args.get("originFilePath").get<std::string>();
+ CHECK_STORAGE_ACCESS(originPath, &out);
CHECK_EXIST(args, "destinationFilePath", out)
+ const std::string& destinationPath = args.get("destinationFilePath").get<std::string>();
+ CHECK_STORAGE_ACCESS(destinationPath, &out);
+
CHECK_EXIST(args, "overwrite", out)
double callback_id = args.get("callbackId").get<double>();
- const std::string& originPath = args.get("originFilePath").get<std::string>();
- const std::string& destinationPath = args.get("destinationFilePath").get<std::string>();
const bool& overwrite = args.get("overwrite").get<bool>();
auto onSuccess = [this, callback_id]() {
@@ -801,7 +1176,7 @@ void FilesystemInstance::CopyTo(const picojson::value& args, picojson::object& o
};
FilesystemManager& fm = FilesystemManager::GetInstance();
- common::TaskQueue::GetInstance().Async(std::bind(&FilesystemManager::CopyTo, &fm, originPath,
+ common::TaskQueue::GetInstance().Queue(std::bind(&FilesystemManager::CopyTo, &fm, originPath,
destinationPath, overwrite, onSuccess, onError));
}
@@ -865,6 +1240,1117 @@ void FilesystemInstance::FileSystemManagerGetCanonicalPath(const picojson::value
FilesystemManager::GetInstance().GetCanonicalPath(path, onSuccess, onError);
}
+namespace {
+
+FILE* OpenFile(const std::string& path, const std::string& fopen_mode) {
+ FILE* file = std::fopen(path.c_str(), fopen_mode.c_str());
+ if (!file) {
+ throw std::system_error{errno, std::generic_category(), "Could not open file"};
+ }
+
+ return file;
+}
+
+FILE* MakeParentsAndOpenFile(const std::string& path, const std::string& fopen_mode) {
+ /*
+ * If fopen fails, created parent directories have to be removed.
+ * Save the path to the first nonexistent parent directory in the file path,
+ * to know where to start recursive removal
+ */
+ std::string first_nonexistent_parent = FilesystemUtils::Dirname(path);
+ struct ::stat buf;
+
+ while (
+ !FilesystemUtils::CheckIfExists(FilesystemUtils::Dirname(first_nonexistent_parent), &buf)) {
+ first_nonexistent_parent = FilesystemUtils::Dirname(first_nonexistent_parent);
+ }
+
+ FilesystemUtils::Mkdir(FilesystemUtils::Dirname(path), true);
+
+ FILE* file = std::fopen(path.c_str(), fopen_mode.c_str());
+ if (file) {
+ return file;
+ }
+
+ std::system_error fopen_error =
+ std::system_error(errno, std::generic_category(), "Could not open file");
+
+ try {
+ FilesystemUtils::RemoveDirectoryRecursively(first_nonexistent_parent);
+ } catch (const std::system_error& error) {
+ LoggerD("Failed to remove created parent directories: %s", error.what());
+ }
+
+ throw fopen_error;
+}
+
+} // namespace
+
+void FilesystemInstance::FileSystemManagerOpenFile(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ const int unique_id = static_cast<int>(args.get("id").get<double>());
+ if (opened_files.find(unique_id) != opened_files.end()) {
+ LogAndReportError(IOException("Internal error (id is already in use)"), out);
+ return;
+ }
+
+ bool access_checked = false;
+ if (WriteAccessRequested(args)) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
+ access_checked = true;
+ }
+
+ if (ReadAccessRequested(args)) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
+ access_checked = true;
+ }
+
+ // File open mode received from JS layer can be different than expected by
+ // WriteAccessRequested and ReadAccessRequested functions. In case like that
+ // privilege would not be checked and user could gain unauthorized access to file.
+ // To prevent this situation we only accept specific open modes.
+ if (false == access_checked) {
+ const std::string& open_mode = args.get("openMode").get<std::string>();
+ LogAndReportError(TypeMismatchException("Invalid open mode: " + open_mode), out);
+ return;
+ }
+
+ const std::string& path = args.get("path").get<std::string>();
+
+ CHECK_STORAGE_ACCESS(path, &out);
+ const std::string open_mode = GetFopenMode(args);
+ FILE* file = nullptr;
+ try {
+ if (ShouldMakeParents(args)) {
+ file = MakeParentsAndOpenFile(path, open_mode);
+ } else {
+ file = OpenFile(path, open_mode);
+ }
+ } catch (const std::system_error& error) {
+ FilesystemUtils::TranslateException(error, out);
+ return;
+ }
+
+ opened_files.emplace(std::make_pair(unique_id, std::make_shared<FileHandle>(file)));
+ ReportSuccess(out);
+}
+
+void FilesystemInstance::FileSystemManagerCreateDirectory(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
+
+ double callback_id = args.get("callbackId").get<double>();
+ const std::string& path = args.get("path").get<std::string>();
+ bool make_parents = args.get("makeParents").get<bool>();
+ CHECK_STORAGE_ACCESS(path, &out);
+
+ common::TaskQueue::GetInstance().Async([this, callback_id, path, make_parents] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+
+ try {
+ FilesystemUtils::Mkdir(path, make_parents);
+ ReportSuccess(picojson::value(path), obj);
+ } catch (const std::system_error& e) {
+ FilesystemUtils::TranslateException(e, obj);
+ }
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ ReportSuccess(out);
+}
+
+void FilesystemInstance::FileSystemManagerDeleteFile(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
+
+ double callback_id = args.get("callbackId").get<double>();
+ const std::string& path = args.get("path").get<std::string>();
+
+ CHECK_STORAGE_ACCESS(path, &out);
+ common::TaskQueue::GetInstance().Async([this, callback_id, path] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+ SCOPE_EXIT {
+ this->PostMessage(response.serialize().c_str());
+ };
+
+ try {
+ struct stat buf {};
+ if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfFile(buf)) {
+ LogAndReportError(NotFoundException("Given path does not point to file."), obj);
+ return;
+ }
+ FilesystemUtils::Unlink(path);
+ ReportSuccess(picojson::value(FilesystemUtils::Dirname(path)), obj);
+ } catch (const std::system_error& e) {
+ FilesystemUtils::TranslateException(e, obj);
+ }
+ });
+
+ ReportSuccess(out);
+}
+
+void FilesystemInstance::FileSystemManagerDeleteDirectory(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
+
+ double callback_id = args.get("callbackId").get<double>();
+ const std::string& path = args.get("path").get<std::string>();
+
+ CHECK_STORAGE_ACCESS(path, &out);
+ bool recursive = args.get("recursive").get<bool>();
+
+ common::TaskQueue::GetInstance().Queue([this, callback_id, path, recursive] {
+ ScopeLogger();
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+ SCOPE_EXIT {
+ this->PostMessage(response.serialize().c_str());
+ };
+
+ try {
+ struct stat buf {};
+ if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfDir(buf)) {
+ LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
+ return;
+ }
+ if (recursive) {
+ FilesystemUtils::RemoveDirectoryRecursively(path);
+ } else {
+ FilesystemUtils::RemoveDirectory(path);
+ }
+ ReportSuccess(picojson::value(FilesystemUtils::Dirname(path)), obj);
+ } catch (const std::system_error& e) {
+ FilesystemUtils::TranslateException(e, obj);
+ }
+ });
+
+ ReportSuccess(out);
+}
+
+void FilesystemInstance::FileSystemManagerCopyFile(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
+
+ double callback_id = args.get("callbackId").get<double>();
+ const std::string& path = args.get("path").get<std::string>();
+ CHECK_STORAGE_ACCESS(path, &out);
+ const std::string& destination_path = args.get("destinationPath").get<std::string>();
+ CHECK_STORAGE_ACCESS(destination_path, &out);
+ bool overwrite = args.get("overwrite").get<bool>();
+
+ common::TaskQueue::GetInstance().Queue([this, callback_id, path, destination_path, overwrite] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+ SCOPE_EXIT {
+ this->PostMessage(response.serialize().c_str());
+ };
+
+ try {
+ struct stat buf {};
+ if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfFile(buf)) {
+ LogAndReportError(NotFoundException("Given path does not point to file."), obj);
+ return;
+ }
+ buf = {};
+ if (FilesystemUtils::CheckIfExists(destination_path, &buf) && !overwrite) {
+ LogAndReportError(
+ IOException("Given path points to an existing resource, overwriting is not allowed."),
+ obj);
+ return;
+ }
+ FilesystemUtils::CopyFile(path, destination_path, overwrite);
+ ReportSuccess(picojson::value(destination_path), obj);
+ } catch (const std::system_error& e) {
+ FilesystemUtils::TranslateException(e, obj);
+ }
+ });
+
+ ReportSuccess(out);
+}
+
+void FilesystemInstance::FileSystemManagerCopyDirectory(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
+ const std::string& path = args.get("path").get<std::string>();
+ CHECK_STORAGE_ACCESS(path, &out);
+ const std::string& destination_path = args.get("destinationPath").get<std::string>();
+ CHECK_STORAGE_ACCESS(destination_path, &out);
+ double callback_id = args.get("callbackId").get<double>();
+ bool overwrite = args.get("overwrite").get<bool>();
+
+ common::TaskQueue::GetInstance().Queue([this, callback_id, path, destination_path, overwrite] {
+ ScopeLogger();
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+ SCOPE_EXIT {
+ this->PostMessage(response.serialize().c_str());
+ };
+
+ try {
+ struct stat buf {};
+ if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfDir(buf)) {
+ LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
+ return;
+ }
+ buf = {};
+ bool exists = FilesystemUtils::CheckIfExists(destination_path, &buf);
+ if (exists && !FilesystemUtils::CheckIfDir(buf)) {
+ LogAndReportError(IOException("File with conflicting name already exists."), obj);
+ return;
+ } else if (!exists) {
+ FilesystemUtils::Mkdir(destination_path);
+ }
+ FilesystemUtils::CopyDirectory(path, destination_path, overwrite);
+ ReportSuccess(picojson::value(destination_path), obj);
+ } catch (const std::system_error& e) {
+ FilesystemUtils::TranslateException(e, obj);
+ }
+ });
+
+ ReportSuccess(out);
+}
+
+void FilesystemInstance::FileSystemManagerMoveFile(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
+
+ const std::string& path = args.get("path").get<std::string>();
+ CHECK_STORAGE_ACCESS(path, &out);
+ const std::string& destination_path = args.get("destinationPath").get<std::string>();
+ CHECK_STORAGE_ACCESS(destination_path, &out);
+ double callback_id = args.get("callbackId").get<double>();
+ bool overwrite = args.get("overwrite").get<bool>();
+
+ common::TaskQueue::GetInstance().Queue([this, callback_id, path, destination_path, overwrite] {
+ ScopeLogger();
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+ SCOPE_EXIT {
+ this->PostMessage(response.serialize().c_str());
+ };
+
+ try {
+ struct stat buf {};
+ if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfFile(buf)) {
+ LogAndReportError(NotFoundException("Given path does not point to file."), obj);
+ return;
+ }
+ buf = {};
+ if (!FilesystemUtils::CheckIfExists(destination_path, &buf) ||
+ !FilesystemUtils::CheckIfDir(buf)) {
+ LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
+ return;
+ }
+
+ buf = {};
+ std::string new_path = destination_path + '/' + FilesystemUtils::PosixBasename(path);
+ if (!overwrite && FilesystemUtils::CheckIfExists(new_path, &buf)) {
+ LogAndReportError(IOException("File or directory with conflicting name already exists."),
+ obj);
+ return;
+ }
+ FilesystemUtils::MoveFile(path, new_path, overwrite);
+ ReportSuccess(picojson::value(new_path), obj);
+ } catch (const std::system_error& e) {
+ FilesystemUtils::TranslateException(e, obj);
+ }
+ });
+
+ ReportSuccess(out);
+}
+
+void FilesystemInstance::FileSystemManagerMoveDirectory(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
+ double callback_id = args.get("callbackId").get<double>();
+ const std::string& path = args.get("path").get<std::string>();
+ CHECK_STORAGE_ACCESS(path, &out);
+ const std::string& destination_path = args.get("destinationPath").get<std::string>();
+ CHECK_STORAGE_ACCESS(destination_path, &out);
+ bool overwrite = args.get("overwrite").get<bool>();
+
+ common::TaskQueue::GetInstance().Queue([this, callback_id, path, destination_path, overwrite] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+ SCOPE_EXIT {
+ this->PostMessage(response.serialize().c_str());
+ };
+
+ try {
+ struct stat buf {};
+ if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfDir(buf)) {
+ LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
+ return;
+ }
+ buf = {};
+ if (!FilesystemUtils::CheckIfExists(destination_path, &buf) ||
+ !FilesystemUtils::CheckIfDir(buf)) {
+ LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
+ return;
+ }
+ buf = {};
+ std::string new_path = destination_path + '/' + FilesystemUtils::PosixBasename(path);
+ if (FilesystemUtils::CheckIfExists(new_path, &buf) && !FilesystemUtils::CheckIfDir(buf)) {
+ LogAndReportError(IOException("File or directory with conflicting name already exists."),
+ obj);
+ return;
+ }
+ FilesystemUtils::MoveDirectory(path, destination_path, overwrite);
+ ReportSuccess(picojson::value(new_path), obj);
+ } catch (const std::system_error& e) {
+ FilesystemUtils::TranslateException(e, obj);
+ }
+ });
+
+ ReportSuccess(out);
+}
+
+void FilesystemInstance::FileSystemManagerRename(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
+ const std::string& path = args.get("path").get<std::string>();
+
+ CHECK_STORAGE_ACCESS(path, &out);
+ double callback_id = args.get("callbackId").get<double>();
+ const std::string& new_name = args.get("newName").get<std::string>();
+
+ common::TaskQueue::GetInstance().Async([this, callback_id, new_name, path] {
+ ScopeLogger();
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+ SCOPE_EXIT {
+ this->PostMessage(response.serialize().c_str());
+ };
+
+ try {
+ struct stat buf {};
+ bool exists = FilesystemUtils::CheckIfExists(path, &buf);
+ if (!exists) {
+ LogAndReportError(NotFoundException("Given path does not point to file or directory."),
+ obj);
+ return;
+ }
+ std::string new_path{FilesystemUtils::Dirname(path) + "/" + new_name};
+ buf = {};
+ exists = FilesystemUtils::CheckIfExists(new_path, &buf);
+ if (exists) {
+ LogAndReportError(IOException("File or directory with conflicting name already exists"),
+ obj);
+ return;
+ }
+ FilesystemUtils::Rename(path, new_path);
+ ReportSuccess(picojson::value(new_path), obj);
+ } catch (const std::system_error& e) {
+ FilesystemUtils::TranslateException(e, obj);
+ }
+ });
+
+ ReportSuccess(out);
+}
+
+void FilterResult(std::vector<const char*>& names, std::vector<unsigned char>& types, bool is_type,
+ unsigned char type) {
+ int i = (int)names.size() - 1;
+
+ while (i >= 0) {
+ if (is_type ? type != types[i] : type == types[i]) {
+ names.erase(names.begin() + i);
+ }
+ i--;
+ }
+}
+
+void FilesystemInstance::FileSystemManagerListDirectory(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
+
+ double callback_id = args.get("callbackId").get<double>();
+ const std::string& path = args.get("path").get<std::string>();
+ const picojson::object& filter = args.get("filter").get<picojson::object>();
+ CHECK_STORAGE_ACCESS(path, &out);
+
+ common::TaskQueue::GetInstance().Async([this, callback_id, path, filter] {
+ ScopeLogger();
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+
+ try {
+ std::vector<const char*> names;
+ {
+ std::vector<unsigned char> types;
+ FilesystemUtils::ListDirectory(path, [&](const char* name, unsigned char type) {
+ names.push_back(name);
+ types.push_back(type);
+ });
+
+ auto it = filter.find("isFile");
+ if (filter.end() != it) {
+ FilterResult(names, types, it->second.get<bool>(), DT_REG);
+ }
+
+ it = filter.find("isDirectory");
+ if (filter.end() != it) {
+ FilterResult(names, types, it->second.get<bool>(), DT_DIR);
+ }
+ }
+
+ auto start_modified_it = filter.find("startModified"),
+ end_modified_it = filter.find("endModified"),
+ start_created_it = filter.find("startCreated"),
+ end_created_it = filter.find("endCreated");
+ if (filter.end() != start_modified_it || filter.end() != end_modified_it ||
+ filter.end() != start_created_it || filter.end() != end_created_it) {
+ auto name_iterator = names.begin();
+ while (name_iterator != names.end()) {
+ struct ::stat buf;
+ std::string path_with_name = path + std::string("/") + std::string(*name_iterator);
+ int status = ::stat(path_with_name.c_str(), &buf);
+ if (status != 0) {
+ throw std::system_error{errno, std::generic_category(),
+ "Failed to get last modification date of a file"};
+ }
+ if (filter.end() != start_modified_it &&
+ (buf.st_mtime < start_modified_it->second.get<double>())) {
+ name_iterator = names.erase(name_iterator);
+ continue;
+ }
+ if (filter.end() != end_modified_it &&
+ (buf.st_mtime > end_modified_it->second.get<double>())) {
+ name_iterator = names.erase(name_iterator);
+ continue;
+ }
+ if (filter.end() != start_created_it &&
+ (buf.st_ctime < start_created_it->second.get<double>())) {
+ name_iterator = names.erase(name_iterator);
+ continue;
+ }
+ if (filter.end() != end_created_it &&
+ (buf.st_ctime > end_created_it->second.get<double>())) {
+ name_iterator = names.erase(name_iterator);
+ continue;
+ }
+ name_iterator++;
+ }
+ }
+
+ picojson::value value = picojson::value(picojson::object());
+ picojson::object& object = value.get<picojson::object>();
+
+ object["names"] = picojson::value{picojson::array_type, true};
+ object["path"] = picojson::value(path);
+
+ picojson::array& names_array = object["names"].get<picojson::array>();
+ names_array.reserve(names.size());
+ for (unsigned int i = 0; i < names.size(); ++i) {
+ names_array.push_back(picojson::value(names[i]));
+ }
+
+ ReportSuccess(value, obj);
+ } catch (const std::system_error& e) {
+ FilesystemUtils::TranslateException(e, obj);
+ }
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ ReportSuccess(out);
+}
+
+void FilesystemInstance::FileSystemManagerIsFile(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
+ const std::string& path = args.get("path").get<std::string>();
+
+ CHECK_STORAGE_ACCESS(path, &out);
+ picojson::value is_file{};
+ try {
+ struct stat buf {};
+ bool exists = FilesystemUtils::CheckIfExists(path, &buf);
+ if (!exists) {
+ LogAndReportError(NotFoundException("Given path does not point to file."), out);
+ return;
+ }
+ is_file = picojson::value{FilesystemUtils::CheckIfFile(buf)};
+ } catch (const std::system_error& e) {
+ FilesystemUtils::TranslateException(e, out);
+ }
+ ReportSuccess(is_file, out);
+}
+
+void FilesystemInstance::FileSystemManagerIsDirectory(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
+ const std::string& path = args.get("path").get<std::string>();
+
+ CHECK_STORAGE_ACCESS(path, &out);
+ picojson::value is_directory{};
+ try {
+ struct stat buf {};
+ bool exists = FilesystemUtils::CheckIfExists(path, &buf);
+ if (!exists) {
+ LogAndReportError(NotFoundException("Given path does not point to directory."), out);
+ return;
+ }
+ is_directory = picojson::value{FilesystemUtils::CheckIfDir(buf)};
+ } catch (const std::system_error& e) {
+ FilesystemUtils::TranslateException(e, out);
+ }
+ ReportSuccess(is_directory, out);
+}
+
+void FilesystemInstance::FileSystemManagerPathExists(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
+ const std::string& path = args.get("path").get<std::string>();
+
+ CHECK_STORAGE_ACCESS(path, &out);
+ picojson::value does_file_exist = picojson::value{true};
+ try {
+ struct stat buf {};
+ bool exists = FilesystemUtils::CheckIfExists(path, &buf);
+ if (!exists) {
+ does_file_exist = picojson::value{false};
+ }
+ } catch (const std::system_error& e) {
+ FilesystemUtils::TranslateException(e, out);
+ }
+ ReportSuccess(does_file_exist, out);
+}
+
+void FilesystemInstance::FileSystemManagerGetLimits(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ picojson::value response =
+ picojson::value{picojson::array{picojson::value{static_cast<double>(NAME_MAX)},
+ picojson::value{static_cast<double>(PATH_MAX)}}};
+ ReportSuccess(response, out);
+}
+
+void FilesystemInstance::FileHandleSeek(const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ const int fh_id = static_cast<int>(args.get("id").get<double>());
+ const long offset = static_cast<long>(args.get("offset").get<double>());
+ const std::string& _whence = args.get("whence").get<std::string>();
+
+ auto fh = opened_files.find(fh_id);
+
+ int whence = SEEK_SET;
+
+ if ("CURRENT" == _whence) {
+ whence = SEEK_CUR;
+ LoggerD("SEEK_CUR selected");
+ } else if ("END" == _whence) {
+ whence = SEEK_END;
+ LoggerD("SEEK_END selected");
+ }
+
+ if (opened_files.end() == fh) {
+ LogAndReportError(IOException("Invalid FileHandle"), out);
+ return;
+ }
+
+ auto handle = fh->second;
+
+ auto logic = [handle, whence, offset](decltype(out) out) {
+ long ret = fseek(handle->file_handle, offset, whence);
+ if (0 != ret) {
+ LoggerE("fseek returned failed");
+ std::string error_message =
+ std::string("seek failed, fileHandle may be corrupted, error message: ") +
+ GetErrorString(errno);
+ LogAndReportError(IOException(error_message.c_str()), out);
+ return;
+ }
+
+ ret = ftell(handle->file_handle);
+ if (-1L == ret) {
+ LoggerE("ftell returned failed");
+ std::string error_message =
+ std::string("seek failed, fileHandle may be corrupted, error message: ") +
+ GetErrorString(errno);
+ LogAndReportError(IOException(error_message.c_str()), out);
+ return;
+ }
+
+ ReportSuccess(picojson::value((double)ret), out);
+ };
+
+ bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
+
+ if (blocking) {
+ logic(out);
+ } else {
+ // Async logic
+ double callback_id = args.get("callbackId").get<double>();
+ this->worker.add_job([this, callback_id, logic] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& async_out = response.get<picojson::object>();
+ async_out["callbackId"] = picojson::value(callback_id);
+ logic(async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ // Sync return
+ ReportSuccess(out);
+ }
+}
+
+void FilesystemInstance::FileHandleReadString(const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ CHECK_EXIST(args, "id", out)
+ const int fh_id = static_cast<int>(args.get("id").get<double>());
+ const std::string& encoding =
+ args.contains("encoding") ? args.get("encoding").get<std::string>() : "UTF-8";
+ if (encoding != kISOEncoding && encoding != kUTF8Encoding) {
+ LogAndReportError(NotSupportedException("Given encoding is not supported."), out);
+ return;
+ }
+
+ auto fh = opened_files.find(fh_id);
+ if (opened_files.end() == fh) {
+ LogAndReportError(IOException("Invalid FileHandle"), out);
+ return;
+ }
+
+ size_t count;
+ bool whole_file = false;
+ if (args.contains("count")) {
+ // If user passed 'count' parameter, we need to read at most 'count' characters.
+ double count_double = args.get("count").get<double>();
+ if (std::string::npos <= static_cast<unsigned long long>(count_double)) {
+ LogAndReportError(InvalidValuesException("Invalid count was given"), out);
+ return;
+ }
+ count = static_cast<size_t>(count_double);
+ } else {
+ try {
+ count = file_size(fh->second->file_handle);
+ whole_file = true;
+ } catch (const std::system_error& e) {
+ LogAndReportError(IOException(e.what()), out);
+ return;
+ }
+ }
+ LoggerD("count: %zu", count);
+
+ auto handle = fh->second;
+
+ auto logic = [handle, count, encoding, whole_file](decltype(out) out) {
+ try {
+ size_t read_bytes = 0;
+ std::vector<std::uint8_t> buf = read_file(handle->file_handle, count, &read_bytes);
+ buf.resize(read_bytes); // this protects from reporting too big arrays to JS
+ if (encoding == kISOEncoding) { // for iso-8859-1 1 byte is equal to 1 character
+ out["result"] = picojson::value(picojson::string_type, true);
+ latin1::to_utf8(buf, out["result"].get<std::string>());
+ ReportSuccess(out);
+ } else { // UTF-8
+ unsigned long char_count;
+ short expected_extension_bytes;
+ if (!validate_and_check_character_count(buf, char_count, expected_extension_bytes)) {
+ LogAndReportError(
+ IOException("File doesn't contain UTF-8 encoded string with given length"), out);
+ return;
+ }
+ LoggerD("char_count: %lu", char_count);
+ LoggerD("ftell: %ld", ftell(handle->file_handle));
+ if (!(std::feof(
+ handle->file_handle))) { // read number of characters if not whole file read
+ LoggerD("count parameter given: %zu", count);
+ if (!whole_file &&
+ !add_utf8_chars_to_buffer(handle->file_handle, buf, count - char_count,
+ expected_extension_bytes)) {
+ LogAndReportError(
+ IOException("File doesn't contain UTF-8 encoded string with given length"), out);
+ }
+ }
+ const char* str = (const char*)buf.data();
+ ReportSuccess(picojson::value{str, buf.size()}, out);
+ }
+ } catch (std::runtime_error& e) {
+ LoggerE("Cannot read, cause: %s", e.what());
+ LogAndReportError(IOException(e.what()), out);
+ }
+ };
+
+ bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
+
+ if (blocking) {
+ logic(out);
+ } else {
+ // Async logic
+ double callback_id = args.get("callbackId").get<double>();
+ this->worker.add_job([this, callback_id, logic] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& async_out = response.get<picojson::object>();
+ async_out["callbackId"] = picojson::value(callback_id);
+ logic(async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ // Sync return
+ ReportSuccess(out);
+ }
+}
+
+void FilesystemInstance::FileHandleWriteString(const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ CHECK_EXIST(args, "id", out)
+ CHECK_EXIST(args, "string", out)
+ const int fh_id = static_cast<int>(args.get("id").get<double>());
+ const std::string& str = args.get("string").get<std::string>();
+ const std::string& encoding =
+ args.contains("encoding") ? args.get("encoding").get<std::string>() : "UTF-8";
+ if (encoding != kISOEncoding && encoding != kUTF8Encoding) {
+ LogAndReportError(NotSupportedException("Given encoding is not supported."), out);
+ return;
+ }
+
+ auto fh = opened_files.find(fh_id);
+ if (opened_files.end() == fh) {
+ LogAndReportError(IOException("Invalid FileHandle"), out);
+ return;
+ }
+
+ auto handle = fh->second;
+
+ auto logic = [str, handle, encoding](decltype(out) out) {
+ try {
+ std::vector<std::uint8_t> data;
+ data.resize(str.size());
+
+ if (encoding == kISOEncoding) {
+ latin1::from_utf8(str, data);
+ } else { // UTF-8
+ LoggerD("copying string memory to vector");
+ std::memcpy(data.data(), str.data(), str.size());
+ }
+ write_file(data.data(), data.size(), handle->file_handle);
+ ReportSuccess(picojson::value{(double)data.size()}, out);
+ } catch (std::runtime_error& e) {
+ LoggerE("Cannot write, cause: %s", e.what());
+ LogAndReportError(IOException(e.what()), out);
+ }
+ };
+
+ bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
+
+ if (blocking) {
+ logic(out);
+ } else {
+ // Async logic
+ double callback_id = args.get("callbackId").get<double>();
+ this->worker.add_job([this, callback_id, logic] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& async_out = response.get<picojson::object>();
+ async_out["callbackId"] = picojson::value(callback_id);
+ logic(async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ // Sync return
+ ReportSuccess(out);
+ }
+}
+
+void FilesystemInstance::FileHandleReadData(const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ CHECK_EXIST(args, "id", out)
+ const int fh_id = static_cast<int>(args.get("id").get<double>());
+ auto fh = opened_files.find(fh_id);
+
+ if (opened_files.end() == fh) {
+ LoggerE("FileHandle with id: %d not found", fh_id);
+ LogAndReportError(IOException("Invalid FileHandle"), out);
+ return;
+ }
+
+ size_t size;
+ // We need to check how many bytes is it possible to read until the EOF.
+ try {
+ // We need to read from file exactly the minimum value of 'size' given by user and the
+ // 'size ' to avoid returning array with redundant data (which would be equal to 0).
+ size = file_bytes_to_eof(fh->second->file_handle);
+ if (args.contains("size")) {
+ // If user passed 'size' parameter, we need to read at most 'size' bytes.
+ double size_double = args.get("size").get<double>();
+ if (std::string::npos <= static_cast<unsigned long long>(size_double)) {
+ LogAndReportError(InvalidValuesException("Invalid size was given"), out);
+ return;
+ }
+ size = std::min(static_cast<size_t>(size_double), size);
+ }
+ } catch (const std::system_error& e) {
+ LogAndReportError(IOException(e.what()), out);
+ return;
+ }
+
+ LoggerD("size: %zu", size);
+
+ auto handle = fh->second;
+
+ auto logic = [handle, size](decltype(out) out) {
+ try {
+ std::vector<std::uint8_t> data = read_file(handle->file_handle, size);
+ out["result"] = picojson::value(picojson::string_type, true);
+ encode_binary_in_string(data, out["result"].get<std::string>());
+ } catch (std::runtime_error& e) {
+ LoggerE("Cannot read, cause: %s", e.what());
+ LogAndReportError(IOException(e.what()), out);
+ }
+ };
+
+ bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
+
+ if (blocking) {
+ logic(out);
+ } else {
+ // Async logic
+ double callback_id = args.get("callbackId").get<double>();
+ this->worker.add_job([this, callback_id, logic] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& async_out = response.get<picojson::object>();
+ async_out["callbackId"] = picojson::value(callback_id);
+ logic(async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ // Sync return
+ ReportSuccess(out);
+ }
+}
+
+void FilesystemInstance::FileHandleWriteData(const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ CHECK_EXIST(args, "id", out)
+ CHECK_EXIST(args, "data", out)
+ const auto& str = args.get("data").get<std::string>();
+ const int fh_id = static_cast<int>(args.get("id").get<double>());
+
+ auto fh = opened_files.find(fh_id);
+ if (opened_files.end() == fh) {
+ LoggerE("FileHandle with id: %d not found", fh_id);
+ LogAndReportError(IOException("Invalid FileHandle"), out);
+ return;
+ }
+
+ auto handle = fh->second;
+
+ auto logic = [str, handle](decltype(out) out) {
+ try {
+ std::vector<std::uint8_t> bytes;
+ decode_binary_from_string(str, bytes);
+ write_file(bytes.data(), bytes.size(), handle->file_handle);
+ } catch (std::runtime_error& e) {
+ LogAndReportError(IOException(e.what()), out);
+ }
+ };
+
+ bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
+
+ if (blocking) {
+ logic(out);
+ } else {
+ // Async logic
+ double callback_id = args.get("callbackId").get<double>();
+ this->worker.add_job([this, callback_id, logic] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& async_out = response.get<picojson::object>();
+ async_out["callbackId"] = picojson::value(callback_id);
+ logic(async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ // Sync return
+ ReportSuccess(out);
+ }
+}
+
+void FilesystemInstance::FileHandleFlush(const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ const int fh_id = static_cast<int>(args.get("id").get<double>());
+
+ auto fh = opened_files.find(fh_id);
+ if (opened_files.end() == fh) {
+ LogAndReportError(IOException("Invalid FileHandle"), out);
+ return;
+ }
+
+ auto handle = fh->second;
+
+ auto logic = [handle](decltype(out) out) {
+ int ret = fflush(handle->file_handle);
+ if (ret) {
+ std::string error_message =
+ std::string("flush failed, error message: ") + GetErrorString(errno);
+ LogAndReportError(IOException(error_message.c_str()), out);
+ }
+ };
+
+ bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
+
+ if (blocking) {
+ logic(out);
+ } else {
+ // Async logic
+ double callback_id = args.get("callbackId").get<double>();
+ this->worker.add_job([this, callback_id, logic] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& async_out = response.get<picojson::object>();
+ async_out["callbackId"] = picojson::value(callback_id);
+ logic(async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ // Sync return
+ ReportSuccess(out);
+ }
+}
+
+void FilesystemInstance::FileHandleSync(const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ const int fh_id = static_cast<int>(args.get("id").get<double>());
+
+ auto fh = opened_files.find(fh_id);
+ if (opened_files.end() == fh) {
+ LogAndReportError(IOException("Invalid FileHandle"), out);
+ return;
+ }
+
+ auto handle = fh->second;
+
+ auto logic = [handle](decltype(out) out) {
+ int ret = fsync(fileno(handle->file_handle));
+ if (ret) {
+ std::string error_message =
+ std::string("sync failed, error message: ") + GetErrorString(errno);
+ LogAndReportError(IOException(error_message.c_str()), out);
+ }
+ };
+
+ bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
+
+ if (blocking) {
+ logic(out);
+ } else {
+ // Async logic
+ double callback_id = args.get("callbackId").get<double>();
+ this->worker.add_job([this, callback_id, logic] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& async_out = response.get<picojson::object>();
+ async_out["callbackId"] = picojson::value(callback_id);
+ logic(async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ // Sync return
+ ReportSuccess(out);
+ }
+}
+
+void FilesystemInstance::FileHandleClose(const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ const int fh_id = static_cast<int>(args.get("id").get<double>());
+ auto fh = opened_files.find(fh_id);
+ if (opened_files.end() == fh) {
+ LogAndReportError(IOException("Invalid FileHandle"), out);
+ return;
+ }
+
+ std::shared_ptr<FileHandle> handle = fh->second;
+ opened_files.erase(fh);
+
+ auto logic = [handle](decltype(out) out) {
+ if (!handle->file_handle) {
+ LogAndReportError(IOException("File handle already closed."), out);
+ return;
+ }
+ int ret = fclose(handle->file_handle);
+ handle->file_handle = nullptr;
+ if (ret) {
+ std::string error_message =
+ std::string("close failed, error message: ") + GetErrorString(errno);
+ LogAndReportError(IOException(error_message.c_str()), out);
+ }
+ };
+
+ bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
+
+ if (blocking) {
+ bool ready = false;
+ bool done = false;
+ std::mutex mutex;
+ std::condition_variable conditional_variable;
+ // adding empty job to worker's queue, in order to wait for all jobs to be done before closing
+ // FILE*
+ this->worker.add_job([] {},
+ [&conditional_variable, &mutex, &ready, &done, logic, &out] {
+ // wait for close
+ std::unique_lock<std::mutex> lock(mutex);
+ conditional_variable.wait(lock, [&ready] { return ready; });
+
+ logic(out);
+ done = true;
+ conditional_variable.notify_one();
+ });
+
+ {
+ // let know that close is ready
+ std::unique_lock<std::mutex> lock(mutex);
+ ready = true;
+ }
+ conditional_variable.notify_one();
+
+ {
+ // wait for worker
+ std::unique_lock<std::mutex> lock(mutex);
+ conditional_variable.wait(lock, [&done] { return done; });
+ }
+ handle->file_handle = nullptr;
+ } else {
+ // Async logic
+ double callback_id = args.get("callbackId").get<double>();
+ this->worker.add_job([this, callback_id, logic] {
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& async_out = response.get<picojson::object>();
+ async_out["callbackId"] = picojson::value(callback_id);
+ logic(async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ // Sync return
+ ReportSuccess(out);
+ }
+}
+
#undef CHECK_EXIST
} // namespace filesystem
diff --git a/src/filesystem/filesystem_instance.h b/src/filesystem/filesystem_instance.h
index 07fb8fa8..2de2da3b 100644
--- a/src/filesystem/filesystem_instance.h
+++ b/src/filesystem/filesystem_instance.h
@@ -17,20 +17,46 @@
#ifndef FILESYSTEM_FILESYSTEM_INSTANCE_H_
#define FILESYSTEM_FILESYSTEM_INSTANCE_H_
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <cerrno>
+#include <cstdio>
#include "common/extension.h"
#include "common/filesystem/filesystem_storage.h"
+#include "common/worker.h"
#include "filesystem/filesystem_manager.h"
#include "filesystem_utils.h"
namespace extension {
namespace filesystem {
+class FileHandle;
+
+typedef std::map<int, std::shared_ptr<FileHandle>> FileHandleMap;
+
+class FileHandle {
+ public:
+ FileHandle(FILE* file_handle) : file_handle(file_handle){};
+ ~FileHandle();
+
+ FileHandle(const FileHandle&) = delete;
+ FileHandle(FileHandle&&) = delete;
+ FileHandle& operator=(const FileHandle&) = delete;
+ FileHandle& operator=(FileHandle&&) = delete;
+
+ FILE* file_handle;
+};
+
class FilesystemInstance : public common::ParsedInstance, FilesystemStateChangeListener {
public:
FilesystemInstance();
virtual ~FilesystemInstance();
private:
+ FileHandleMap opened_files;
+ common::Worker worker;
+
void FileCreateSync(const picojson::value& args, picojson::object& out);
void FileRename(const picojson::value& args, picojson::object& out);
void FileStat(const picojson::value& args, picojson::object& out);
@@ -54,6 +80,70 @@ class FilesystemInstance : public common::ParsedInstance, FilesystemStateChangeL
void onFilesystemStateChangeSuccessCallback(const common::Storage& storage);
void PrepareError(const FilesystemError& error, picojson::object& out);
void FileSystemManagerGetCanonicalPath(const picojson::value& args, picojson::object& out);
+
+ void FileSystemManagerOpenFile(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerCreateDirectory(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerDeleteFile(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerDeleteDirectory(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerCopyFile(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerCopyDirectory(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerMoveFile(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerMoveDirectory(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerRename(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerListDirectory(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerIsFile(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerIsDirectory(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerPathExists(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerToURI(const picojson::value& args, picojson::object& out);
+ void FileSystemManagerGetLimits(const picojson::value& args, picojson::object& out);
+
+ /**
+ * @brief wrapper for std::fseek function.
+ * Sets the file position indicator for the file stream stream.
+ * @parameter out has always set status, either success or error.
+ */
+ void FileHandleSeek(const picojson::value& args, picojson::object& out);
+
+ /**
+ * @brief Reads file contents as string.
+ * @parameter out has always set status, either success or error.
+ * In case of success, string value is passed.
+ */
+ void FileHandleReadString(const picojson::value& args, picojson::object& out);
+
+ /**
+ * @brief Writes string to file.
+ * @parameter out has always set status, either success or error.
+ */
+ void FileHandleWriteString(const picojson::value& args, picojson::object& out);
+
+ /**
+ * @brief Reads file contents as binary data, can use worker and not block GUI.
+ * @parameter out has always set status, either success or error.
+ * In case of success, encoded uint8_t array is passed.
+ */
+ void FileHandleReadData(const picojson::value& args, picojson::object& out);
+
+ /**
+ * @brief Writes binary data to file, can use worker and not block GUI.
+ * @parameter out has always set status, either success or error.
+ */
+ void FileHandleWriteData(const picojson::value& args, picojson::object& out);
+
+ /**
+ * @brief wrapper for std::fflush function.
+ * Writes any unwritten data from the stream's buffer to the associated output device.
+ * @parameter out has always set status, either success or error.
+ */
+ void FileHandleFlush(const picojson::value& args, picojson::object& out);
+ void FileHandleSync(const picojson::value& args, picojson::object& out);
+
+ /**
+ * @brief wrapper for std::fclose function.
+ * Closes the given file stream.
+ * @parameter out has always set status, either success or error.
+ */
+ void FileHandleClose(const picojson::value& args, picojson::object& out);
};
} // namespace filesystem
diff --git a/src/filesystem/filesystem_manager.cc b/src/filesystem/filesystem_manager.cc
index 755defb5..8ca885d3 100644
--- a/src/filesystem/filesystem_manager.cc
+++ b/src/filesystem/filesystem_manager.cc
@@ -196,7 +196,7 @@ FilesystemError make_directory_worker(const std::string& path) {
}
}
- std::string parent_path = FilesystemUtils::get_dirname(path);
+ std::string parent_path = FilesystemUtils::GetDirname(path);
auto parent_result = make_directory_worker(parent_path);
if (parent_result == FilesystemError::DirectoryExists) {
@@ -289,8 +289,7 @@ void FilesystemManager::MakeDirectory(const std::string& path,
result_cb(make_directory_worker(path));
}
-// pass oldPath by copy to prevent possible TOCTOU bug
-void FilesystemManager::Rename(const std::string oldPath, const std::string& newPath,
+void FilesystemManager::Rename(const std::string& oldPath, const std::string& newPath,
const std::function<void(const FilesystemStat&)>& success_cb,
const std::function<void(FilesystemError)>& error_cb) {
ScopeLogger();
diff --git a/src/filesystem/filesystem_manager.h b/src/filesystem/filesystem_manager.h
index eaadf9ba..e0d2d12b 100644
--- a/src/filesystem/filesystem_manager.h
+++ b/src/filesystem/filesystem_manager.h
@@ -69,7 +69,7 @@ class FilesystemManager {
const std::function<void(const FilesystemStat&)>& success_cb,
const std::function<void(FilesystemError)>& error_cb);
- void Rename(const std::string oldPath, const std::string& newPath,
+ void Rename(const std::string& oldPath, const std::string& newPath,
const std::function<void(const FilesystemStat&)>& success_cb,
const std::function<void(FilesystemError)>& error_cb);
diff --git a/src/filesystem/filesystem_stat.cc b/src/filesystem/filesystem_stat.cc
index bb5bc89b..feb7bed6 100644
--- a/src/filesystem/filesystem_stat.cc
+++ b/src/filesystem/filesystem_stat.cc
@@ -59,8 +59,7 @@ picojson::value FilesystemStat::toJSON() const {
return retval;
}
-// pass path by copy to prevent possible TOCTOU bug
-FilesystemStat FilesystemStat::getStat(const std::string path) {
+FilesystemStat FilesystemStat::getStat(const std::string& path) {
ScopeLogger();
struct stat aStatObj;
FilesystemStat _result;
diff --git a/src/filesystem/filesystem_stat.h b/src/filesystem/filesystem_stat.h
index 31c58875..a984ab1d 100755
--- a/src/filesystem/filesystem_stat.h
+++ b/src/filesystem/filesystem_stat.h
@@ -49,7 +49,7 @@ class FilesystemStat {
picojson::value toJSON() const;
- static FilesystemStat getStat(const std::string path);
+ static FilesystemStat getStat(const std::string& path);
};
} // namespace filesystem
} // namespace extension
diff --git a/src/filesystem/filesystem_utils.cc b/src/filesystem/filesystem_utils.cc
index c6d04e5a..00b8c819 100644
--- a/src/filesystem/filesystem_utils.cc
+++ b/src/filesystem/filesystem_utils.cc
@@ -14,27 +14,350 @@
* limitations under the License.
*/
#include "filesystem_utils.h"
+#include "common/logger.h"
+#include "common/platform_exception.h"
+#include <dirent.h>
+#include <fcntl.h>
+#include <ftw.h>
#include <glib.h>
#include <libgen.h>
-#include "common/logger.h"
+#include <sys/sendfile.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
namespace FilesystemUtils {
-std::string get_storage_dir_path(int id, storage_directory_e typeToCheck) {
+using namespace std::string_literals;
+using namespace common;
+using common::tools::ReportError;
+using common::tools::GetErrorString;
+
+void Mkdir(const std::string& path) {
+ ScopeLogger("%s", path.c_str());
+ int ret = ::mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+
+ if (0 != ret) {
+ throw std::system_error{errno, std::generic_category()};
+ }
+}
+
+void Mkdir(const std::string& path, bool parents) {
+ // ScopeLogger("%s, %d", path.c_str(), parents); // disabled in recursive function
+ if (!parents) {
+ Mkdir(path);
+ return;
+ }
+
+ struct ::stat buf;
+ std::vector<std::string> stack;
+ // iterate path up to first existing element
+ for (std::string s = path; 0 != ::stat(s.c_str(), &buf); s = Dirname(s)) {
+ if (ENOENT == errno) {
+ stack.push_back(s);
+ } else {
+ throw std::system_error{errno, std::generic_category()};
+ }
+ }
+
+ if (stack.empty()) { // this means, that path exists, let Mkdir handle error
+ Mkdir(path);
+ return;
+ }
+
+ // from top to bottom
+ for (auto rit = stack.rbegin(); rit != stack.rend(); ++rit) {
+ try {
+ Mkdir(*rit);
+ } catch (const std::system_error& error) {
+ if (stack.rbegin() != rit) {
+ try {
+ RemoveDirectoryRecursively(*stack.rbegin());
+ } catch (const std::system_error& removalError) {
+ LoggerW(
+ "Could not remove parent directories created so far: %s."
+ "Some of them might still exist",
+ removalError.what());
+ }
+ }
+ throw;
+ }
+ }
+}
+
+void Unlink(const std::string& path) {
ScopeLogger();
- char* platformPath = NULL;
- int result = storage_get_directory(id, typeToCheck, &platformPath);
- if (STORAGE_ERROR_NONE != result) {
- LoggerD("Cannot retrieve path for type %i: %d (%s)", typeToCheck, result,
- get_error_message(result));
- return std::string();
+ int ret = ::unlink(path.c_str());
+ if (0 != ret) {
+ throw std::system_error{errno, std::generic_category()};
}
- std::string path = std::string(platformPath);
- free(platformPath);
- return path;
}
-std::string get_dirname(const std::string& path) {
+std::string PosixBasename(const std::string& path) {
+ ScopeLogger();
+ char* s = ::strdup(path.c_str());
+ if (!s) {
+ throw std::system_error{errno, std::generic_category(), path};
+ }
+
+ // basename will never fail
+ std::string name{::basename(s)};
+ free(s);
+ return name;
+}
+
+std::string Dirname(const std::string& path) {
+ ScopeLogger();
+ char* s = ::strdup(path.c_str());
+ if (!s) {
+ throw std::system_error{errno, std::generic_category(), path};
+ }
+ // dirname will never fail
+ std::string dir{::dirname(s)};
+ free(s);
+ return dir;
+}
+
+void CopyFileOverExistingDirectory(const std::string& src, const std::string& dest,
+ bool overwrite) {
+ ScopeLogger("From: %s, To %s", src.c_str(), dest.c_str());
+ struct stat buf {};
+ if (CheckIfExists(dest, &buf) && CheckIfDir(buf)) {
+ if (overwrite) {
+ RemoveDirectoryRecursively(dest);
+ } else {
+ throw std::system_error{EIO, std::generic_category(),
+ "Failed to copy file: overwrite is not allowed."};
+ }
+ }
+ CopyFile(src, dest, overwrite);
+}
+
+void CopyFile(const std::string& src, const std::string& dest, bool overwrite) {
+ ScopeLogger("From: %s; To %s", src.c_str(), dest.c_str());
+
+ GError* error = nullptr;
+ auto source_ptr = std::unique_ptr<GFile, decltype(&g_object_unref)>(
+ g_file_new_for_path(src.c_str()), g_object_unref);
+ auto dest_ptr = std::unique_ptr<GFile, decltype(&g_object_unref)>(
+ g_file_new_for_path(dest.c_str()), g_object_unref);
+ int flags = G_FILE_COPY_ALL_METADATA;
+ if (overwrite) {
+ flags |= G_FILE_COPY_OVERWRITE;
+ }
+
+ gboolean success =
+ g_file_copy(source_ptr.get(), dest_ptr.get(), static_cast<GFileCopyFlags>(flags), nullptr,
+ nullptr, nullptr, &error);
+ if (!success) {
+ std::string why{};
+ if (error) {
+ why = error->message;
+ g_error_free(error);
+ }
+ throw std::system_error{EIO, std::generic_category(), "Failed to copy file: "s + why};
+ }
+}
+
+void CopyDirectory(const std::string& src, const std::string& dest, bool overwrite) {
+ ScopeLogger("From: %s, To %s", src.c_str(), dest.c_str());
+ ListDirectory(src, [&](const char* name, unsigned char type) {
+ if (DT_DIR == type) {
+ std::string dest_dir = dest + '/' + name;
+ struct stat buf {};
+ bool exists = CheckIfExists(dest_dir, &buf);
+ if (exists && !CheckIfDir(buf)) {
+ if (overwrite) {
+ Unlink(dest_dir);
+ Mkdir(dest_dir);
+ } else {
+ throw std::system_error{EIO, std::generic_category(),
+ "Failed to copy directory: overwriting is not allowed."};
+ }
+ } else if (!exists) {
+ Mkdir(dest_dir);
+ }
+
+ CopyDirectory(src + '/' + name, dest_dir, overwrite);
+ } else { // copying of regular files as well as other types of items pointed by src
+ CopyFileOverExistingDirectory(src + '/' + name, dest + '/' + name, overwrite);
+ }
+ // Set errno to 0 to prevent from reporting readdir error after successful iterating through
+ // directory.
+ errno = 0;
+ });
+}
+
+void ListDirectory(const std::string& path, std::function<void(const char*, unsigned char)> next) {
+ ScopeLogger("%s", path.c_str());
+ DIR* d = ::opendir(path.c_str());
+ if (nullptr == d) {
+ throw std::system_error{errno, std::generic_category(),
+ "Failed to open directory: "s + GetErrorString(errno)};
+ }
+
+ std::unique_ptr<DIR, void (*)(DIR*)> dir_ptr(d, [](DIR* d) {
+ if (::closedir(d)) {
+ LoggerW("closedir failed");
+ }
+ });
+ errno = 0;
+
+ for (dirent* entry; (entry = ::readdir(d));) {
+ if (0 == std::strcmp(entry->d_name, ".") || 0 == std::strcmp(entry->d_name, "..")) {
+ continue;
+ }
+ next(entry->d_name, entry->d_type);
+ }
+
+ if (0 != errno) {
+ throw std::system_error{errno, std::generic_category(),
+ "Failed to read directory: "s + GetErrorString(errno)};
+ }
+}
+
+void RemoveDirectoryRecursively(const std::string& path) {
+ ScopeLogger("%s", path.c_str());
+ auto res =
+ nftw(path.c_str(),
+ [](const char* fpath, const struct stat* sb, int typeflag, struct FTW* ftwbuf) -> int {
+ // if number of nested directories is large
+ // below log could decrease readability
+ // ScopeLogger("%s", fpath);
+
+ auto res = remove(fpath);
+ if (res) {
+ LoggerD("Failed to remove %s: %s", fpath, GetErrorString(errno).c_str());
+ return errno;
+ }
+ return 0;
+ },
+ 128, FTW_DEPTH | FTW_PHYS);
+
+ if (res) {
+ if (-1 == res) {
+ // -1 can be returned by nftw() function, to prevent invalid translation of error in
+ // std::system_error constructor, such situation will be treated as generic IOError
+ res = EIO;
+ }
+ throw std::system_error{res, std::generic_category(),
+ "Failed to remove directory recursively: "s + GetErrorString(res)};
+ }
+}
+
+void RemoveDirectory(const std::string& path) {
+ ScopeLogger();
+ if (rmdir(path.c_str())) {
+ throw std::system_error{errno, std::generic_category(), "Failed to remove directory"};
+ }
+}
+
+std::string RealPath(const std::string& path) {
+ ScopeLogger();
+ char* real_path = realpath(path.c_str(), nullptr);
+ if (nullptr == real_path) {
+ throw std::system_error{errno, std::generic_category(), "Path is not valid."};
+ }
+ std::string s{real_path};
+ free(real_path);
+ return s;
+}
+
+bool CheckIfExists(const std::string& path, struct stat* buf) {
+ ScopeLogger();
+ if (stat(path.c_str(), buf)) {
+ if (ENOENT == errno) {
+ return false;
+ } else {
+ throw std::system_error{errno, std::generic_category(),
+ "Unable to check file existence: "s + GetErrorString(errno)};
+ }
+ }
+ return true;
+}
+
+bool CheckIfDir(const struct stat& buf) {
+ ScopeLogger();
+ if (S_ISDIR(buf.st_mode)) {
+ return true;
+ }
+ return false;
+}
+
+bool CheckIfFile(const struct stat& buf) {
+ ScopeLogger();
+ if (S_ISREG(buf.st_mode)) {
+ return true;
+ }
+ return false;
+}
+
+void Rename(const std::string& path, const std::string& new_path) {
+ ScopeLogger();
+ if (::rename(path.c_str(), new_path.c_str())) {
+ throw std::system_error{errno, std::generic_category(),
+ "Unable to rename file or directory: "s + GetErrorString(errno)};
+ }
+}
+
+void MoveFile(const std::string& path, const std::string& new_path, bool overwrite) {
+ ScopeLogger();
+ GError* error = nullptr;
+ auto source_ptr = std::unique_ptr<GFile, decltype(&g_object_unref)>(
+ g_file_new_for_path(path.c_str()), g_object_unref);
+ auto dest_ptr = std::unique_ptr<GFile, decltype(&g_object_unref)>(
+ g_file_new_for_path(new_path.c_str()), g_object_unref);
+ int flags = G_FILE_COPY_ALL_METADATA;
+ if (overwrite) {
+ flags |= G_FILE_COPY_OVERWRITE;
+ }
+ gboolean success =
+ g_file_move(source_ptr.get(), dest_ptr.get(), static_cast<GFileCopyFlags>(flags), nullptr,
+ nullptr, nullptr, &error);
+ if (!success) {
+ std::string why{};
+ if (error) {
+ why = error->message;
+ g_error_free(error);
+ }
+ throw std::system_error{EIO, std::generic_category(), "Failed to move file: "s + why};
+ }
+}
+
+void MoveDirectory(const std::string& src, const std::string& dest, bool overwrite) {
+ ScopeLogger("%s %s", src.c_str(), dest.c_str());
+ struct stat buf {};
+ const std::string& new_path = dest + '/' + PosixBasename(src);
+ // If directories are on the same mount point, we can simply try to rename them.
+ // However, it might be done only if new_path does not exist because move_directory should merge
+ // directories.
+ if (!CheckIfExists(new_path, &buf)) {
+ LoggerD("new_path %s", new_path.c_str());
+ auto result = ::rename(src.c_str(), new_path.c_str());
+ if (!result) {
+ return;
+ } else if (EXDEV != errno) {
+ // The directories are in the same mount point, but the operation has just failed.
+ throw std::system_error{EIO, std::generic_category(),
+ "Unable to move directory: "s + GetErrorString(errno)};
+ }
+ }
+
+ // Move directory to other move point.
+ CopyDirectory(src, dest, overwrite);
+ RemoveDirectoryRecursively(src);
+}
+
+void TranslateException(const std::system_error& e, picojson::object& obj) {
+ ScopeLogger();
+ if (std::errc::no_such_file_or_directory == e.code()) {
+ LogAndReportError(NotFoundException(e.what()), obj);
+ } else {
+ LogAndReportError(IOException(e.what()), obj);
+ }
+}
+
+std::string GetDirname(const std::string& path) {
ScopeLogger();
char* dir = g_path_get_dirname(path.c_str());
if (dir) {
@@ -45,11 +368,4 @@ std::string get_dirname(const std::string& path) {
return std::string(".");
}
}
-
-std::string get_basename(const std::string& path) {
- ScopeLogger();
- // basename will modify content: pass a copy
- std::string buf = path.c_str();
- return std::string(basename(const_cast<char*>(buf.c_str())));
-}
}
diff --git a/src/filesystem/filesystem_utils.h b/src/filesystem/filesystem_utils.h
index f59048e9..58882847 100644
--- a/src/filesystem/filesystem_utils.h
+++ b/src/filesystem/filesystem_utils.h
@@ -17,9 +17,16 @@
#ifndef FILESYSTEM_FILESYSTEM_UTILS_H
#define FILESYSTEM_FILESYSTEM_UTILS_H
-#include <storage-expand.h>
-#include <string>
#include "common/picojson.h"
+#include "common/tools.h"
+
+#include <gio/gio.h>
+#include <glib-object.h>
+#include <sys/stat.h>
+#include <functional>
+#include <memory>
+#include <string>
+#include <system_error>
namespace extension {
namespace filesystem {
@@ -40,14 +47,111 @@ enum class FilesystemError {
namespace FilesystemUtils {
/**
- * @brief get_storage_dir_path attempts to get path from storage.
- * If path cannot be retrieved then an empty string is returned.
- *
+ * @brief Wrapper for POSIX mkdir function.
+ * @throw std::system_error
+ */
+void Mkdir(const std::string& path);
+
+/**
+ * @brief Make directory using mkdir. If 'parents' is true, make parent directories as needed
+ * @throw std::system_error
*/
-std::string get_storage_dir_path(int id, storage_directory_e typeToCheck);
+void Mkdir(const std::string& path, bool parents);
+
+/**
+ * @brief Wrapper for POSIX unlink function
+ * @throw std::system_error
+ */
+void Unlink(const std::string& path);
+
+/**
+ * @brief Returns last element of path (wrapper for POSIX basename function)
+ * @throw std::system_error
+ */
+std::string PosixBasename(const std::string& path);
+
+/**
+ * @brief Returns parent directory of path (wrapper for POSIX dirname function)
+ * @throw std::system_error
+ */
+std::string Dirname(const std::string& path);
+
+/**
+ * @brief Wrapper for GLib g_file_copy function.
+ * @throw std::system_error
+ */
+void CopyFile(const std::string& src, const std::string& dest, bool overwrite);
+
+/**
+ * @brief Copies directory recursively
+ * @throw std::system_error
+ */
+void CopyDirectory(const std::string& src, const std::string& dest, bool overwrite);
+
+/**
+ * @brief Calls 'next' function with name for every entry in given directory
+ * @throw std::system_error
+ */
+void ListDirectory(const std::string& path, std::function<void(const char*, unsigned char)> next);
+
+/**
+ * @brief Removes directory recursively pointed by path.
+ * @throw std::system_error
+ */
+void RemoveDirectoryRecursively(const std::string& path);
+
+/**
+ * @brief Removes directory pointed by path.
+ * @throw std::system_error
+ */
+void RemoveDirectory(const std::string& path);
+
+/**
+ * @brief Returns the real path.
+ * @throw std::system_error
+ */
+std::string RealPath(const std::string& path);
+
+/**
+ * @brief Checks if path points to file or directory.
+ * @throw std::system_error
+ */
+bool CheckIfExists(const std::string& path, struct stat* buf);
+
+/**
+ * @brief Checks if path points to directory.
+ * @throw std::system_error
+ */
+bool CheckIfDir(const struct stat& buf);
+
+/**
+ * @brief Checks if path points to file.
+ * @throw std::system_error
+ */
+bool CheckIfFile(const struct stat& buf);
+
+/**
+ * @brief Renames file or directory.
+ * @throw std::system_error
+ */
+void Rename(const std::string& path, const std::string& new_path);
+
+/**
+ * @brief Wrapper for GLib g_file_move function.
+ * @throw std::system_error
+ */
+void MoveFile(const std::string& path, const std::string& new_path, bool overwrite);
+
+/**
+ * @brief Moves directory by recursively calling move_file.
+ * @throw std::system_error
+ */
+void MoveDirectory(const std::string& path, const std::string& new_path, bool overwrite);
+
+void TranslateException(const std::system_error& e, picojson::object& obj);
-std::string get_dirname(const std::string& path);
-std::string get_basename(const std::string& path);
+// This function is left only for compatibility with previous implementation in FilesystemManager
+std::string GetDirname(const std::string& path);
}
#endif // FILESYSTEM_FILESYSTEM_UTILS_H
diff --git a/src/filesystem/js/common.js b/src/filesystem/js/common.js
index 30dc3594..f90e6537 100644
--- a/src/filesystem/js/common.js
+++ b/src/filesystem/js/common.js
@@ -22,17 +22,39 @@ var validator_ = privUtils_.validator;
var types_ = validator_.Types;
var native_ = new xwalk.utils.NativeManager(extension);
+/*
+ * Create new array-like object of numbers: UTF-16 char codes from string.
+ * As type pass Array, Uint8Array, etc.
+ * Useful for passing data through crosswalk.
+ */
+function StringToArray(str, type) {
+ var len = str.length;
+ var output = new type(len);
+ for (var i = 0; i < len; i++) {
+ output[i] = str.charCodeAt(i);
+ }
+ return output;
+}
+
+/*
+ * Pass array-like object of numbers (Array, Uint8Array, etc.), returns string.
+ * Each char has codepoint equal to value from array cropped with & 0xFF
+ * Useful for passing data through crosswalk.
+ */
+function ArrayToString(data) {
+ var output = '';
+ var len = data.length;
+ for (var i = 0; i < len; i++) {
+ output += String.fromCharCode(data[i] & 0xff); // conversion to octet
+ }
+ return output;
+}
+
function SetReadOnlyProperty(obj, n, v) {
- Object.defineProperty(obj, n, {
- value: v,
- writable: false
- });
+ Object.defineProperty(obj, n, { value: v, writable: false });
}
-var FileSystemStorageType = {
- INTERNAL: 'INTERNAL',
- EXTERNAL: 'EXTERNAL'
-};
+var FileSystemStorageType = { INTERNAL: 'INTERNAL', EXTERNAL: 'EXTERNAL' };
var FileSystemStorageState = {
MOUNTED: 'MOUNTED',
@@ -40,17 +62,14 @@ var FileSystemStorageState = {
UNMOUNTABLE: 'UNMOUNTABLE'
};
-var FileMode = {
- r: 'r',
- rw: 'rw',
- w: 'w',
- a: 'a'
-};
+var FileMode = { a: 'a', r: 'r', rw: 'rw', rwo: 'rwo', w: 'w' };
+
+var BaseSeekPosition = { BEGIN: 'BEGIN', CURRENT: 'CURRENT', END: 'END' };
var tizen24home = '/opt/usr/media';
-// this variable need to match same variable
-// in common/filesystem/filesystem_provider_storage.cc
+// this variable need to match same variable in
+// common/filesystem/filesystem_provider_storage.cc
var kVirtualRootImages = 'images';
var commonFS_ = (function() {
@@ -244,9 +263,10 @@ var commonFS_ = (function() {
} else {
_fileRealPath = aPath;
}
- // this line makes that '.' and '..' is supported in paths,
- // but each method handle those cases
- // and return error (see commonFS_.checkPathWithoutDots() method)
+ // removeDotsFromPath execution here, results with '.' and '..' beeing
+ // supported in paths, next methods throw an error when getting argument
+ // with '.' or '..' in it
+ // (see commonFS_.checkPathWithoutDots() method)
_fileRealPath = removeDotsFromPath(_fileRealPath);
// convert path to be compatibile with previous version of Tizen
// (global paths usage issue workaround)
@@ -386,11 +406,7 @@ var commonFS_ = (function() {
}
function cloneStorage(storage) {
- return {
- label: storage.label,
- type: storage.type,
- state: storage.state
- };
+ return { label: storage.label, type: storage.type, state: storage.state };
}
function getStorage(label) {
@@ -438,6 +454,7 @@ var commonFS_ = (function() {
f_isSubDir: f_isSubDir,
f_isCorrectRelativePath: f_isCorrectRelativePath,
getStorage: getStorage,
- getAllStorages: getAllStorages
+ getAllStorages: getAllStorages,
+ mergeMultipleSlashes: mergeMultipleSlashes
};
})();
diff --git a/src/filesystem/js/file.js b/src/filesystem/js/file.js
index aa6fb1ed..0848a8d2 100644
--- a/src/filesystem/js/file.js
+++ b/src/filesystem/js/file.js
@@ -60,6 +60,11 @@ function File(data) {
}
function toURI() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: File.toURI() is deprecated since Tizen 5.0. ' +
+ 'Use FileSystemManager.toURI() instead.'
+ );
+
xwalk.utils.checkPrivilegeAccess(xwalk.utils.privilege.FILESYSTEM_READ);
return 'file://' + commonFS_.toRealPath(this.fullPath);
}
@@ -71,10 +76,10 @@ File.prototype.toURI = function() {
function stringToRegex(str) {
var _regString = '^';
if (str === '') {
- return new RegExp(_regString, 'i');
+ return new RegExp(_regString + '$', 'i');
}
- // single '\' sign is not visible in JS string,
- // escaping % wildcard need to be done by '\\%'
+ // single '\' sign is not visible in JS string, escaping % wildcard need to
+ // be done by '\\%'
str = str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
var _percentTokens = str.split('%');
@@ -82,8 +87,8 @@ function stringToRegex(str) {
for (i = 0; i < _percentTokens.length - 1; ++i) {
_regString = _regString + _percentTokens[i];
if (_regString[_regString.length - 1] === '\\') {
- // special handling \\% sequence - '%' sign
- // is threaten as regular sign - not wildcard
+ // special handling \\% sequence - '%' sign is threaten as
+ // regular sign - not wildcard
_regString = _regString.split('');
_regString.pop();
_regString = _regString.join('') + '%';
@@ -165,6 +170,11 @@ function checkFile(file, fileFilter) {
}
function listFiles() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: File.listFiles() is deprecated since Tizen 5.0. ' +
+ 'Use FileSystemManager.listDirectory() instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
{ name: 'onsuccess', type: types_.FUNCTION },
{ name: 'onerror', type: types_.FUNCTION, optional: true, nullable: true },
@@ -253,6 +263,11 @@ function _checkEncoding(encoding) {
}
function openStream() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: File.openStream() is deprecated since Tizen 5.0. ' +
+ 'Use FileHandle interface to read/write operations instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
{ name: 'mode', type: types_.ENUM, values: ['r', 'rw', 'w', 'a'] },
{ name: 'onsuccess', type: types_.FUNCTION },
@@ -309,6 +324,11 @@ File.prototype.openStream = function() {
};
function readAsText() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: File.readAsText() is deprecated since Tizen 5.0. ' +
+ 'Use FileHandle.readString() or FileHandle.readStringNonBlocking() instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
{ name: 'onsuccess', type: types_.FUNCTION },
{ name: 'onerror', type: types_.FUNCTION, optional: true, nullable: true },
@@ -364,6 +384,12 @@ File.prototype.readAsText = function() {
};
function copyTo() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: File.copyTo() is deprecated since Tizen 5.0. ' +
+ 'Use FileSystemManager.CopyFile() or FileSystemManager.CopyDirectory() ' +
+ 'instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
{ name: 'originFilePath', type: types_.STRING },
{ name: 'destinationFilePath', type: types_.STRING },
@@ -560,6 +586,12 @@ File.prototype.copyTo = function() {
};
function moveTo() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: File.moveTo() is deprecated since Tizen 5.0. ' +
+ 'Use FileSystemManager.moveFile() or FileSystemManager.moveDirectory() ' +
+ 'instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
{ name: 'originFilePath', type: types_.STRING },
{ name: 'destinationFilePath', type: types_.STRING },
@@ -710,6 +742,11 @@ File.prototype.moveTo = function() {
};
function createDirectory() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: File.createDirectory() is deprecated since Tizen 5.0. ' +
+ 'Use FileSystemManager.createDirectory() instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
{ name: 'dirPath', type: types_.STRING }
]);
@@ -788,6 +825,11 @@ File.prototype.createDirectory = function() {
};
function createFile() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: File.createFile() is deprecated since Tizen 5.0. ' +
+ 'Use FileSystemManager.createFile() instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
{ name: 'relativeFilePath', type: types_.STRING }
]);
@@ -855,6 +897,11 @@ File.prototype.createFile = function() {
};
function resolveFile() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: File.resolve() is deprecated since Tizen 5.0. ' +
+ 'Use FileHandle and FileSystemManager interfaces instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
{ name: 'filePath', type: types_.STRING }
]);
@@ -915,6 +962,11 @@ File.prototype.resolve = function() {
};
function deleteDirectory() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: File.deleteDirectory() is deprecated since Tizen 5.0. ' +
+ 'Use FileSystemManager.deleteDirectory() instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
{ name: 'directoryPath', type: types_.STRING },
{ name: 'recursive', type: types_.BOOLEAN },
@@ -1044,6 +1096,11 @@ File.prototype.deleteDirectory = function() {
};
function deleteFile() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: File.deleteFile() is deprecated since Tizen 5.0. ' +
+ 'Use FileSystemManager.deleteFile() instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
{ name: 'filePath', type: types_.STRING },
{ name: 'onsuccess', type: types_.FUNCTION, optional: true, nullable: true },
diff --git a/src/filesystem/js/file_handle.js b/src/filesystem/js/file_handle.js
new file mode 100644
index 00000000..47ab9836
--- /dev/null
+++ b/src/filesystem/js/file_handle.js
@@ -0,0 +1,802 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function FileHandle(_id, _path, _mode) {
+ Object.defineProperties(this, {
+ id: { value: _id, writable: false, enumerable: false },
+ path: { value: _path, writable: false, enumerable: true },
+ mode: { value: _mode, writable: false, enumerable: false },
+ state: { value: 'opened', writable: true, enumerable: false }
+ });
+}
+
+FileHandle.prototype.seek = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'offset', type: types_.LONG },
+ {
+ name: 'whence',
+ type: types_.ENUM,
+ values: type_.getValues(BaseSeekPosition),
+ optional: true
+ }
+ ]);
+
+ if (!(this.state === 'opened')) {
+ throw new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened');
+ }
+ var data = { id: this.id, offset: args.offset };
+ if (undefined === args.whence) {
+ data.whence = 'BEGIN';
+ } else {
+ data.whence = args.whence;
+ }
+ var result = native_.callSync('FileHandle_seek', data);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+ return native_.getResultObject(result);
+};
+
+FileHandle.prototype.seekNonBlocking = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'offset', type: types_.LONG },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
+ {
+ name: 'whence',
+ type: types_.ENUM,
+ values: type_.getValues(BaseSeekPosition),
+ optional: true
+ }
+ ]);
+
+ if (!(this.state === 'opened')) {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened')
+ );
+ }, 0);
+ return;
+ }
+ var data = { id: this.id, offset: args.offset, blocking: false };
+ if (undefined === args.whence) {
+ data.whence = 'BEGIN';
+ } else {
+ data.whence = args.whence;
+ }
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ native_.callIfPossible(args.successCallback, native_.getResultObject(result));
+ }
+ };
+
+ var result = native_.call('FileHandle_seek', data, callback);
+ if (native_.isFailure(result)) {
+ setTimeout(function() {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ }, 0);
+ }
+};
+
+FileHandle.prototype.readString = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'count', type: types_.LONG, optional: true, nullable: true },
+ { name: 'inputEncoding', type: types_.STRING, optional: true }
+ ]);
+ if (!(this.state === 'opened')) {
+ throw new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened');
+ }
+ if (this.mode === 'w' || this.mode === 'a') {
+ throw new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is write-only'
+ );
+ }
+ var data = { id: this.id, encoding: args.inputEncoding };
+ if (!type_.isNullOrUndefined(args.count)) {
+ data.count = args.count;
+ }
+ var result = native_.callSync('FileHandle_readString', data);
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+ return native_.getResultObject(result);
+};
+
+FileHandle.prototype.readStringNonBlocking = function() {
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
+ { name: 'count', type: types_.LONG, optional: true },
+ { name: 'inputEncoding', type: types_.STRING, optional: true }
+ ]);
+ if (!(this.state === 'opened')) {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened')
+ );
+ }, 0);
+ return;
+ }
+ if (this.mode === 'w' || this.mode === 'a') {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is write-only'
+ )
+ );
+ }, 0);
+ return;
+ }
+ var data = { id: this.id, encoding: args.inputEncoding, blocking: false };
+ if (!type_.isNullOrUndefined(args.count)) {
+ data.count = args.count;
+ }
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ native_.callIfPossible(args.successCallback, native_.getResultObject(result));
+ }
+ };
+
+ var result = native_.call('FileHandle_readString', data, callback);
+
+ if (native_.isFailure(result)) {
+ var err = native_.getErrorObject(result);
+ if ('IOError' === err.name) {
+ setTimeout(function() {
+ native_.callIfPossible(args.errorCallback, err);
+ }, 0);
+ } else {
+ throw native_.getErrorObject(result);
+ }
+ }
+};
+
+FileHandle.prototype.writeString = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'string', type: types_.STRING },
+ { name: 'outputEncoding', type: types_.STRING, optional: true }
+ ]);
+ if (!('opened' === this.state)) {
+ throw new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened');
+ }
+ if ('r' === this.mode) {
+ throw new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is read-only'
+ );
+ }
+ var data = { id: this.id, string: args.string, encoding: args.outputEncoding };
+ var result = native_.callSync('FileHandle_writeString', data);
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+ return native_.getResultObject(result);
+};
+
+FileHandle.prototype.writeStringNonBlocking = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'string', type: types_.STRING },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
+ { name: 'outputEncoding', type: types_.STRING, optional: true }
+ ]);
+ if (!('opened' === this.state)) {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened')
+ );
+ }, 0);
+ return;
+ }
+ if ('r' === this.mode) {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is read-only'
+ )
+ );
+ }, 0);
+ return;
+ }
+ var data = {
+ id: this.id,
+ string: args.string,
+ encoding: args.outputEncoding,
+ blocking: false
+ };
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ native_.callIfPossible(args.successCallback, native_.getResultObject(result));
+ }
+ };
+
+ var result = native_.call('FileHandle_writeString', data, callback);
+
+ if (native_.isFailure(result)) {
+ var err = native_.getErrorObject(result);
+ if ('IOError' === err.name) {
+ setTimeout(function() {
+ native_.callIfPossible(args.errorCallback, err);
+ }, 0);
+ } else {
+ throw native_.getErrorObject(result);
+ }
+ }
+};
+
+FileHandle.prototype.readBlob = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'size', type: types_.LONG, optional: true }
+ ]);
+
+ if (!(this.state === 'opened')) {
+ throw new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened');
+ }
+ if (this.mode === 'w' || this.mode === 'a') {
+ throw new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is write-only'
+ );
+ }
+ var data = { id: this.id };
+ if (!type_.isNullOrUndefined(args.size)) {
+ data.size = args.size;
+ }
+ var result = native_.call('FileHandle_readData', data);
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+ var encodedData = native_.getResultObject(result);
+ var data = StringToArray(encodedData, Uint8Array);
+ return new Blob([data]);
+};
+
+FileHandle.prototype.readBlobNonBlocking = function() {
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
+ { name: 'size', type: types_.LONG, optional: true, nullable: true }
+ ]);
+ if (!(this.state === 'opened')) {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened')
+ );
+ }, 0);
+ return;
+ }
+
+ var data = { id: this.id, blocking: false };
+ if (!type_.isNullOrUndefined(args.size)) {
+ data.size = args.size;
+ }
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ var encodedData = native_.getResultObject(result);
+ var data = StringToArray(encodedData, Uint8Array);
+ native_.callIfPossible(args.successCallback, new Blob([data]));
+ }
+ };
+
+ var result = native_.call('FileHandle_readData', data, callback);
+
+ if (native_.isFailure(result)) {
+ var err = native_.getErrorObject(result);
+ if ('IOError' === err.name) {
+ setTimeout(function() {
+ native_.callIfPossible(args.errorCallback, err);
+ }, 0);
+ } else {
+ throw native_.getErrorObject(result);
+ }
+ }
+};
+
+function blobToUint8Array(b) {
+ var uri = URL.createObjectURL(b),
+ xhr = new XMLHttpRequest(),
+ i,
+ ui8;
+ xhr.open('GET', uri, false);
+ xhr.send();
+ URL.revokeObjectURL(uri);
+ var stringUtf8 = unescape(encodeURIComponent(xhr.response));
+ ui8 = new Uint8Array(stringUtf8.length);
+ for (i = 0; i < stringUtf8.length; ++i) {
+ ui8[i] = stringUtf8.charCodeAt(i);
+ }
+ return ui8;
+}
+
+FileHandle.prototype.writeBlob = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'blob', type: types_.PLATFORM_OBJECT, values: Blob }
+ ]);
+ if (!(this.state === 'opened')) {
+ throw new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened');
+ }
+ if (this.mode === 'r') {
+ throw new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is read-only'
+ );
+ }
+
+ var encodedData = ArrayToString(blobToUint8Array(args.blob));
+ var data = { id: this.id, data: encodedData };
+ var result = native_.callSync('FileHandle_writeData', data);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileHandle.prototype.writeBlobNonBlocking = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'blob', type: types_.PLATFORM_OBJECT, values: Blob },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+ if (!('opened' === this.state)) {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened')
+ );
+ }, 0);
+ return;
+ } else if (this.mode === 'r') {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is read-only'
+ )
+ );
+ }, 0);
+ return;
+ }
+
+ var encodedData = ArrayToString(blobToUint8Array(args.blob));
+ var data = { id: this.id, data: encodedData, blocking: false };
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ native_.callIfPossible(args.successCallback, native_.getResultObject(result));
+ }
+ };
+
+ var result = native_.call('FileHandle_writeData', data, callback);
+
+ // Only IOError is possible to be returned synchronously, so it is passed to
+ // errorCallback in each case.
+ if (native_.isFailure(result)) {
+ setTimeout(function() {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ }, 0);
+ return;
+ }
+};
+
+FileHandle.prototype.readData = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'size', type: types_.LONG, optional: true }
+ ]);
+ if (!(this.state === 'opened')) {
+ throw new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened');
+ }
+ if (this.mode === 'w' || this.mode === 'a') {
+ throw new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is write-only'
+ );
+ }
+ var data = { id: this.id };
+ if (!type_.isNullOrUndefined(args.size)) {
+ data.size = args.size;
+ }
+ var result = native_.callSync('FileHandle_readData', data);
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+ var encodedData = native_.getResultObject(result);
+ var data = StringToArray(encodedData, Uint8Array);
+ return new Uint8Array(data);
+};
+
+FileHandle.prototype.readDataNonBlocking = function() {
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
+ { name: 'size', type: types_.LONG, optional: true, nullable: true }
+ ]);
+ if (!(this.state === 'opened')) {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened')
+ );
+ }, 0);
+ return;
+ }
+ if (this.mode === 'w' || this.mode === 'a') {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is write-only'
+ )
+ );
+ }, 0);
+ return;
+ }
+
+ var data = { id: this.id, blocking: false };
+ if (!type_.isNullOrUndefined(args.size)) {
+ data.size = args.size;
+ }
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ var data_out = new Uint8Array(
+ StringToArray(native_.getResultObject(result), Uint8Array)
+ );
+ native_.callIfPossible(args.successCallback, data_out);
+ }
+ };
+
+ var result = native_.call('FileHandle_readData', data, callback);
+
+ if (native_.isFailure(result)) {
+ var err = native_.getErrorObject(result);
+ if ('IOError' === err.name) {
+ setTimeout(function() {
+ native_.callIfPossible(args.errorCallback, err);
+ }, 0);
+ } else {
+ throw native_.getErrorObject(result);
+ }
+ }
+};
+
+FileHandle.prototype.writeData = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'data', type: types_.PLATFORM_OBJECT, values: Uint8Array }
+ ]);
+ if (!(this.state === 'opened')) {
+ throw new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened');
+ } else if (this.mode === 'r') {
+ throw new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is read-only'
+ );
+ }
+ var encodedData = ArrayToString(args.data);
+ var data = { id: this.id, data: encodedData };
+ var result = native_.callSync('FileHandle_writeData', data);
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileHandle.prototype.writeDataNonBlocking = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'data', type: types_.PLATFORM_OBJECT, values: Uint8Array },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+ if (!('opened' === this.state)) {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened')
+ );
+ }, 0);
+ return;
+ } else if (this.mode === 'r') {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is read-only'
+ )
+ );
+ }, 0);
+ return;
+ }
+
+ var encodedData = ArrayToString(args.data);
+
+ var data = { id: this.id, data: encodedData, blocking: false };
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ native_.callIfPossible(args.successCallback, native_.getResultObject(result));
+ }
+ };
+
+ var result = native_.call('FileHandle_writeData', data, callback);
+
+ // Only IOError is possible to be returned synchronously, so it is passed to
+ // errorCallback in each case.
+ if (native_.isFailure(result)) {
+ setTimeout(function() {
+ native_.callIfPossible(args.errorCallback, err);
+ }, 0);
+ }
+};
+
+FileHandle.prototype.flush = function() {
+ if (!(this.state === 'opened')) {
+ throw new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened');
+ }
+ if (this.mode === 'r') {
+ throw new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is read-only'
+ );
+ }
+ var data = { id: this.id };
+ var result = native_.callSync('FileHandle_flush', data);
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileHandle.prototype.flushNonBlocking = function() {
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+ if (!(this.state === 'opened')) {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened')
+ );
+ }, 0);
+ return;
+ }
+ if (this.mode === 'r') {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is read-only'
+ )
+ );
+ }, 0);
+ return;
+ }
+ var data = { id: this.id, blocking: false };
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ native_.callIfPossible(args.successCallback, native_.getResultObject(result));
+ }
+ };
+
+ var result = native_.call('FileHandle_flush', data, callback);
+
+ // Only IOError is possible to be returned synchronously, so it is passed to
+ // errorCallback in each case.
+ if (native_.isFailure(result)) {
+ setTimeout(function() {
+ native_.callIfPossible(args.errorCallback, err);
+ }, 0);
+ }
+};
+
+FileHandle.prototype.sync = function() {
+ if (!(this.state === 'opened')) {
+ throw new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened');
+ }
+ if (this.mode === 'r') {
+ throw new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is read-only'
+ );
+ }
+
+ var data = { id: this.id };
+ var result = native_.callSync('FileHandle_sync', data);
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileHandle.prototype.syncNonBlocking = function() {
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+ if (!(this.state === 'opened')) {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened')
+ );
+ }, 0);
+ return;
+ }
+ if (this.mode === 'r') {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(
+ WebAPIException.IO_ERR,
+ 'FileHandle state is read-only'
+ )
+ );
+ }, 0);
+ return;
+ }
+ var data = { id: this.id, blocking: false };
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ native_.callIfPossible(args.successCallback, native_.getResultObject(result));
+ }
+ };
+
+ var result = native_.call('FileHandle_sync', data, callback);
+
+ // Only IOError is possible to be returned synchronously, so it is passed to
+ // errorCallback in each case.
+ if (native_.isFailure(result)) {
+ setTimeout(function() {
+ native_.callIfPossible(args.errorCallback, err);
+ }, 0);
+ }
+};
+
+FileHandle.prototype.close = function() {
+ if (!(this.state === 'opened')) {
+ throw new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened');
+ }
+ var data = { id: this.id };
+ var result = native_.callSync('FileHandle_close', data);
+ this.state = 'closed';
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileHandle.prototype.closeNonBlocking = function() {
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+ if (!(this.state === 'opened')) {
+ setTimeout(function() {
+ native_.callIfPossible(
+ args.errorCallback,
+ new WebAPIException(WebAPIException.IO_ERR, 'FileHandle is not opened')
+ );
+ }, 0);
+ return;
+ }
+
+ var data = { id: this.id, blocking: false };
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ native_.callIfPossible(args.successCallback, native_.getResultObject(result));
+ }
+ };
+
+ var result = native_.call('FileHandle_close', data, callback);
+ this.state = 'closed';
+
+ // Only IOError is possible to be returned synchronously, so it is passed to
+ // errorCallback in each case.
+ if (native_.isFailure(result)) {
+ setTimeout(function() {
+ native_.callIfPossible(args.errorCallback, err);
+ }, 0);
+ }
+};
diff --git a/src/filesystem/js/file_stream.js b/src/filesystem/js/file_stream.js
index abc389d1..61add68f 100644
--- a/src/filesystem/js/file_stream.js
+++ b/src/filesystem/js/file_stream.js
@@ -47,28 +47,12 @@ function FileStream(data, mode, encoding) {
set: function(v) {},
enumerable: true
},
- _mode: {
- value: mode,
- writable: false,
- enumerable: false
- },
- _encoding: {
- value: encoding,
- writable: false,
- enumerable: false
- },
- _file: {
- value: data,
- writable: false,
- enumerable: false
- },
- _closed: {
- value: false,
- writable: true,
- enumerable: false
- },
- _rewrite: {
- value: mode === 'w' ? true : false,
+ _mode: { value: mode, writable: false, enumerable: false },
+ _encoding: { value: encoding, writable: false, enumerable: false },
+ _file: { value: data, writable: false, enumerable: false },
+ _closed: { value: false, writable: true, enumerable: false },
+ _truncate: {
+ value: mode === 'w', // 'w' truncates file to zero length
writable: true,
enumerable: false
}
@@ -82,6 +66,11 @@ function _checkClosed(stream) {
}
function closeFileStream() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: FileStream.close() is deprecated since Tizen 5.0. ' +
+ 'Use FileHandle.close() instead.'
+ );
+
this._closed = true;
}
@@ -101,32 +90,14 @@ function _checkWriteAccess(mode) {
}
}
-/* returns array of numbers */
-function string_to_array(str) {
- var output = [];
- var len = str.length;
- for (var i = 0; i < len; i++) {
- output.push(str.charCodeAt(i));
- }
- return output;
-}
-
-/* receives array of numbers, returns string */
-function array_to_string(data) {
- var output = '';
- var len = data.length;
- for (var i = 0; i < len; i++) {
- output += String.fromCharCode(data[i] & 0xff); // conversion to octet
- }
- return output;
-}
-
function read() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: FileStream.read() is deprecated since Tizen 5.0. ' +
+ 'Use FileHandle.readString() or FileHandle.readStringNonBlocking() instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
- {
- name: 'charCount',
- type: types_.LONG
- }
+ { name: 'charCount', type: types_.LONG }
]);
_checkClosed(this);
@@ -186,10 +157,7 @@ FileStream.prototype.read = function() {
function readBytes() {
var args = validator_.validateArgs(arguments, [
- {
- name: 'byteCount',
- type: types_.LONG
- }
+ { name: 'byteCount', type: types_.LONG }
]);
_checkClosed(this);
@@ -215,7 +183,7 @@ function readBytes() {
throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Could not read');
}
- var decoded = string_to_array(native_.getResultObject(result));
+ var decoded = StringToArray(native_.getResultObject(result), Array);
if (decoded.length) {
can_change_size = true;
@@ -229,10 +197,21 @@ function readBytes() {
}
FileStream.prototype.readBytes = function() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: FileStream.readBytes() is deprecated since Tizen 5.0. ' +
+ 'Use FileHandle.readData() or FileHandle.readDataNonBlocking() instead.'
+ );
+
return readBytes.apply(this, arguments);
};
FileStream.prototype.readBase64 = function() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: FileStream.readBase64() is deprecated since Tizen 5.0. ' +
+ 'Use FileHandle.readData() or FileHandle.readDataNonBlocking() in ' +
+ 'combination with atob() and btoa() functions instead.'
+ );
+
return base64_encode(readBytes.apply(this, arguments));
};
@@ -249,11 +228,13 @@ function check_characters_outside_latin1(str) {
}
function write() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: FileStream.write() is deprecated since Tizen 5.0. ' +
+ 'Use FileHandle.writeString() or FileHandle.writeStringNonBlocking() instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
- {
- name: 'stringData',
- type: types_.STRING
- }
+ { name: 'stringData', type: types_.STRING }
]);
_checkClosed(this);
@@ -271,7 +252,7 @@ function write() {
encoding: this._encoding,
offset: this.position,
data: args.stringData,
- rewrite: this._rewrite
+ truncate: this._truncate
};
if (data.encoding == 'iso-8859-1') {
@@ -286,7 +267,7 @@ function write() {
can_change_size = true;
this.position = this.position + args.stringData.length;
can_change_size = false;
- this._rewrite = false;
+ this._truncate = false;
}
FileStream.prototype.write = function() {
@@ -294,12 +275,17 @@ FileStream.prototype.write = function() {
};
function writeBytes() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: FileStream.writeBytes() is deprecated since Tizen 5.0. ' +
+ 'Use FileHandle.writeData() or FileHandle.writeDataNonBlocking() instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
{
name: 'byteData',
type: types_.ARRAY,
- values: undefined /* was types_.OCTET, but checking moved to
- array_to_string for performance */
+ values: undefined /* was types_.OCTET, but checking moved to ArrayToString for
+ performance */
}
]);
@@ -316,8 +302,8 @@ function writeBytes() {
var data = {
location: commonFS_.toRealPath(this._file.fullPath),
offset: this.position,
- data: array_to_string(args.byteData),
- rewrite: this._rewrite
+ data: ArrayToString(args.byteData),
+ truncate: this._truncate
};
var result = native_.callSync('File_writeBytes', data);
@@ -328,7 +314,7 @@ function writeBytes() {
can_change_size = true;
this.position = this.position + args.byteData.length;
can_change_size = false;
- this._rewrite = false;
+ this._truncate = false;
}
FileStream.prototype.writeBytes = function() {
@@ -336,11 +322,14 @@ FileStream.prototype.writeBytes = function() {
};
function writeBase64() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: FileStream.writeBase64() is deprecated since Tizen 5.0. ' +
+ 'Use FileHandle.writeData() or FileHandle.writeDataNonBlocking() in ' +
+ 'combination with atob() and btoa() functions instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
- {
- name: 'base64Data',
- type: types_.STRING
- }
+ { name: 'base64Data', type: types_.STRING }
]);
_checkClosed(this);
@@ -350,7 +339,7 @@ function writeBase64() {
location: commonFS_.toRealPath(this._file.fullPath),
offset: this.position,
data: args.base64Data,
- rewrite: this._rewrite
+ truncate: this._truncate
};
var result = native_.callSync('File_writeBase64', data);
@@ -364,7 +353,7 @@ function writeBase64() {
can_change_size = true;
this.position += written_bytes;
can_change_size = false;
- this._rewrite = false;
+ this._truncate = false;
}
FileStream.prototype.writeBase64 = function() {
diff --git a/src/filesystem/js/file_system_manager.js b/src/filesystem/js/file_system_manager.js
index 4de93738..943453fc 100755..100644
--- a/src/filesystem/js/file_system_manager.js
+++ b/src/filesystem/js/file_system_manager.js
@@ -22,15 +22,595 @@ function FileSystemStorage(data) {
});
}
-var PATH_MAX = 4096;
+var FileStreamManager = function() {
+ this.nextId = 0;
+};
+
+FileStreamManager.prototype.getNextFileHandleId = function() {
+ return ++this.nextId;
+};
+
+var fileStreamManager = new FileStreamManager();
function FileSystemManager() {
+ var limits = native_.getResultObject(native_.callSync('FileSystemManager_getLimits'));
Object.defineProperties(this, {
- maxPathLength: { value: PATH_MAX, writable: false, enumerable: true }
+ maxNameLength: { value: limits[0], writable: false, enumerable: true },
+ maxPathLength: { value: limits[1], writable: false, enumerable: true }
});
}
+FileSystemManager.prototype.openFile = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING },
+ { name: 'openMode', type: types_.ENUM, values: type_.getValues(FileMode) },
+ { name: 'makeParents', type: types_.BOOLEAN, optional: true }
+ ]);
+
+ if (!args.has.makeParents) {
+ args.makeParents = true;
+ }
+
+ var data = {
+ path: commonFS_.toRealPath(args.path),
+ openMode: args.openMode,
+ makeParents: args.makeParents,
+ id: fileStreamManager.getNextFileHandleId()
+ };
+
+ if (!data.path) {
+ throw new WebAPIException(
+ WebAPIException.NOT_FOUND_ERR,
+ 'Invalid path: ' + args.path
+ );
+ }
+
+ var result = native_.callSync('FileSystemManager_openFile', data);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ } else {
+ return new FileHandle(data.id, args.path, args.openMode);
+ }
+};
+
+FileSystemManager.prototype.createDirectory = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING },
+ { name: 'makeParents', type: types_.BOOLEAN, optional: true },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+
+ if (!args.has.makeParents) {
+ args.makeParents = true;
+ }
+
+ var data = { path: commonFS_.toRealPath(args.path), makeParents: args.makeParents };
+
+ if (!data.path) {
+ throw new WebAPIException(
+ WebAPIException.INVALID_VALUES_ERR,
+ 'Invalid path: ' + args.path
+ );
+ }
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ var path = native_.getResultObject(result);
+ native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
+ }
+ };
+
+ var result = native_.call('FileSystemManager_createDirectory', data, callback);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileSystemManager.prototype.deleteFile = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+
+ var data = { path: commonFS_.toRealPath(args.path) };
+
+ if (!data.path) {
+ throw new WebAPIException(
+ WebAPIException.INVALID_VALUES_ERR,
+ 'Invalid path: ' + args.path
+ );
+ }
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ var path = native_.getResultObject(result);
+ native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
+ }
+ };
+
+ var result = native_.call('FileSystemManager_deleteFile', data, callback);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileSystemManager.prototype.deleteDirectory = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING },
+ { name: 'recursive', type: types_.BOOLEAN, optional: true },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+
+ if (!args.has.recursive) {
+ args.recursive = true;
+ }
+
+ var realPath = commonFS_.toRealPath(args.path);
+ if (!realPath) {
+ throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
+ }
+
+ var data = { path: realPath, recursive: args.recursive };
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ var path = native_.getResultObject(result);
+ native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
+ }
+ };
+
+ var result = native_.call('FileSystemManager_deleteDirectory', data, callback);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileSystemManager.prototype.copyFile = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING },
+ { name: 'destinationPath', type: types_.STRING },
+ { name: 'overwrite', type: types_.BOOLEAN, optional: true },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+
+ if (!args.has.overwrite) {
+ args.overwrite = false;
+ }
+
+ var data = {
+ path: commonFS_.toRealPath(args.path),
+ destinationPath: commonFS_.toRealPath(args.destinationPath),
+ overwrite: args.overwrite
+ };
+
+ if (!data.path) {
+ throw new WebAPIException(
+ WebAPIException.INVALID_VALUES_ERR,
+ 'Invalid path: ' + args.path
+ );
+ }
+ if (!data.destinationPath) {
+ throw new WebAPIException(
+ WebAPIException.INVALID_VALUES_ERR,
+ 'Invalid path: ' + args.destinationPath
+ );
+ }
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ var path = native_.getResultObject(result);
+ native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
+ }
+ };
+
+ var result = native_.call('FileSystemManager_copyFile', data, callback);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileSystemManager.prototype.copyDirectory = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING },
+ { name: 'destinationPath', type: types_.STRING },
+ { name: 'overwrite', type: types_.BOOLEAN, optional: true },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+
+ var realPath = commonFS_.toRealPath(args.path);
+ var realDestinationPath = commonFS_.toRealPath(args.destinationPath);
+ if (!realPath || !realDestinationPath) {
+ throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
+ }
+
+ if (!args.has.overwrite) {
+ args.overwrite = false;
+ }
+
+ var data = {
+ path: realPath,
+ destinationPath: realDestinationPath,
+ overwrite: args.overwrite
+ };
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ var path = native_.getResultObject(result);
+ native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
+ }
+ };
+
+ var result = native_.call('FileSystemManager_copyDirectory', data, callback);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileSystemManager.prototype.moveFile = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING },
+ { name: 'destinationPath', type: types_.STRING },
+ { name: 'overwrite', type: types_.BOOLEAN, optional: true },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+
+ var realPath = commonFS_.toRealPath(args.path);
+ var realDestinationPath = commonFS_.toRealPath(args.destinationPath);
+ if (!realPath || !realDestinationPath) {
+ throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
+ }
+
+ if (!args.has.overwrite) {
+ args.overwrite = false;
+ }
+
+ var data = {
+ path: realPath,
+ destinationPath: realDestinationPath,
+ overwrite: args.overwrite
+ };
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ var path = native_.getResultObject(result);
+ native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
+ }
+ };
+
+ var result = native_.call('FileSystemManager_moveFile', data, callback);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileSystemManager.prototype.moveDirectory = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING },
+ { name: 'destinationPath', type: types_.STRING },
+ { name: 'overwrite', type: types_.BOOLEAN, optional: true },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+
+ var realPath = commonFS_.toRealPath(args.path);
+ var realDestinationPath = commonFS_.toRealPath(args.destinationPath);
+ if (!realPath || !realDestinationPath) {
+ throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
+ }
+
+ if (!args.has.overwrite) {
+ args.overwrite = false;
+ }
+
+ var data = {
+ path: realPath,
+ destinationPath: realDestinationPath,
+ overwrite: args.overwrite
+ };
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ var path = native_.getResultObject(result);
+ native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
+ }
+ };
+
+ var result = native_.call('FileSystemManager_moveDirectory', data, callback);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileSystemManager.prototype.rename = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING },
+ { name: 'newName', type: types_.STRING },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+
+ if (-1 !== args.newName.indexOf('/') || -1 !== args.newName.indexOf('\x00')) {
+ throw new WebAPIException(
+ WebAPIException.INVALID_VALUES_ERR,
+ 'newName contains invalid character.'
+ );
+ }
+
+ var realPath = commonFS_.toRealPath(args.path);
+ if (!realPath) {
+ throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
+ }
+
+ var data = { path: realPath, newName: args.newName };
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ var path = native_.getResultObject(result);
+ native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
+ }
+ };
+
+ var result = native_.call('FileSystemManager_rename', data, callback);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+function throwIfNotDate(argument, name) {
+ if (argument instanceof Date) {
+ return true;
+ }
+ throw new WebAPIException(
+ WebAPIException.TYPE_MISMATCH_ERR,
+ 'Argument "' + name + '" in a filter is not of type Date.'
+ );
+}
+
+FileSystemManager.prototype.listDirectory = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING },
+ { name: 'successCallback', type: types_.FUNCTION, optional: true },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
+ { name: 'filter', type: types_.DICTIONARY, optional: true, nullable: true }
+ ]);
+
+ if (!args.has.filter) {
+ args.filter = {};
+ }
+
+ if (args.filter.hasOwnProperty('startModified')) {
+ throwIfNotDate(args.filter.startModified, 'startModified');
+ args.filter.startModified = args.filter.startModified.getTime() / 1000;
+ }
+ if (args.filter.hasOwnProperty('endModified')) {
+ throwIfNotDate(args.filter.endModified, 'endModified');
+ args.filter.endModified = args.filter.endModified.getTime() / 1000;
+ }
+ if (args.filter.hasOwnProperty('startCreated')) {
+ throwIfNotDate(args.filter.startCreated, 'startCreated');
+ args.filter.startCreated = args.filter.startCreated.getTime() / 1000;
+ }
+ if (args.filter.hasOwnProperty('endCreated')) {
+ throwIfNotDate(args.filter.endCreated, 'endCreated');
+ args.filter.endCreated = args.filter.endCreated.getTime() / 1000;
+ }
+
+ var data = { path: commonFS_.toRealPath(args.path), filter: args.filter };
+
+ if (!data.path) {
+ throw new WebAPIException(
+ WebAPIException.INVALID_VALUES_ERR,
+ 'Invalid path: ' + args.path
+ );
+ }
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ var obj = native_.getResultObject(result);
+ var names = obj.names;
+ if (args.filter.hasOwnProperty('name')) {
+ var regex_name = stringToRegex(args.filter.name);
+ for (var i = names.length - 1; i >= 0; i--) {
+ if (!regex_name.test(names[i])) {
+ names.splice(i, 1);
+ }
+ }
+ }
+ native_.callIfPossible(
+ args.successCallback,
+ names,
+ commonFS_.toVirtualPath(obj.path)
+ );
+ }
+ };
+
+ var result = native_.call('FileSystemManager_listDirectory', data, callback);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
+FileSystemManager.prototype.toURI = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING }
+ ]);
+
+ // The toRealPath function will convert any string to absolute path, if possible.
+ // The function returns undefined for path, which starts with not-existing
+ // virtual root.
+ var realPath = commonFS_.toRealPath(args.path);
+
+ if (!realPath) {
+ throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
+ }
+
+ return 'file://' + realPath;
+};
+
+FileSystemManager.prototype.isFile = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING }
+ ]);
+ // The toRealPath function will convert any string to absolute path, if possible.
+ // The function returns undefined for path, which starts with not-existing
+ // virtual root.
+ var realPath = commonFS_.toRealPath(args.path);
+
+ if (!realPath) {
+ throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
+ }
+
+ var data = { path: realPath };
+
+ var result = native_.callSync('FileSystemManager_isFile', data);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ } else {
+ return native_.getResultObject(result);
+ }
+};
+
+FileSystemManager.prototype.isDirectory = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING }
+ ]);
+ // The toRealPath function will convert any string to absolute path, if possible.
+ // The function returns undefined for path, which starts with not-existing
+ // virtual root.
+ var realPath = commonFS_.toRealPath(args.path);
+
+ if (!realPath) {
+ throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
+ }
+
+ var data = { path: realPath };
+
+ var result = native_.callSync('FileSystemManager_isDirectory', data);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ } else {
+ return native_.getResultObject(result);
+ }
+};
+
+FileSystemManager.prototype.pathExists = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING }
+ ]);
+ // The toRealPath function will convert any string to absolute path, if possible.
+ // The function returns undefined for path, which starts with not-existing
+ // virtual root.
+ var realPath = commonFS_.toRealPath(args.path);
+
+ if (!realPath) {
+ throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
+ }
+ var data = { path: realPath };
+
+ var result = native_.callSync('FileSystemManager_pathExists', data);
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ } else {
+ return native_.getResultObject(result);
+ }
+};
+
+FileSystemManager.prototype.getDirName = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'path', type: types_.STRING }
+ ]);
+ var path = args.path;
+
+ path = commonFS_.mergeMultipleSlashes(path);
+ if (path.startsWith('file://')) {
+ path = path.substring('file://'.length - 1, path.length - 1);
+ }
+
+ if (path.startsWith('/') && 0 === path.lastIndexOf('/')) {
+ // handle the "/" and "/file.ext"
+ return '/';
+ } else if (path.endsWith('/')) {
+ // cut the last '/'
+ path = path.substring(0, path.length - 1);
+ }
+
+ var index = path.lastIndexOf('/');
+ if (-1 !== index) {
+ path = path.substring(0, index); // cut the directory/file the path points to
+ }
+ return path;
+};
+
function resolve() {
+ privUtils_.warn(
+ 'DEPRECATION WARNING: FileSystemManager.resolve() is deprecated since ' +
+ 'Tizen 5.0. Use FileHandle and FileSystemManager interfaces instead.'
+ );
+
var args = validator_.validateArgs(arguments, [
{ name: 'location', type: types_.STRING },
{ name: 'onsuccess', type: types_.FUNCTION },
@@ -46,6 +626,12 @@ function resolve() {
if (!args.has.mode) {
args.mode = 'rw';
+ } else if ('rwo' == args.mode) {
+ throw new WebAPIException(
+ WebAPIException.INVALID_VALUES_ERR,
+ 'rwo mode was introduced in version 5.0 and is not supported in earlier ' +
+ 'version methods'
+ );
}
// resolving a path on unmounted storage should result in exception
@@ -86,10 +672,7 @@ function resolve() {
setTimeout(function() {
native_.callIfPossible(
args.onerror,
- new WebAPIException(
- WebAPIException.NOT_FOUND_ERR,
- 'Specified virtual root does not exist.'
- )
+ new WebAPIException(WebAPIException.NOT_FOUND_ERR, 'Invalid path.')
);
}, 0);
return;
@@ -110,9 +693,7 @@ function resolve() {
return;
}
- var data = {
- location: _realPath
- };
+ var data = { location: _realPath };
var callback = function(result) {
if (native_.isFailure(result)) {
diff --git a/src/humanactivitymonitor/humanactivitymonitor_api.js b/src/humanactivitymonitor/humanactivitymonitor_api.js
index 4f635f48..8397d1af 100755
--- a/src/humanactivitymonitor/humanactivitymonitor_api.js
+++ b/src/humanactivitymonitor/humanactivitymonitor_api.js
@@ -15,6 +15,7 @@
*/
var utils_ = xwalk.utils;
+var privilege_ = utils_.privilege;
var type_ = utils_.type;
var converter_ = utils_.converter;
var validator_ = utils_.validator;
@@ -43,7 +44,9 @@ var HumanActivityType = {
WRIST_UP: 'WRIST_UP',
HRM: 'HRM',
GPS: 'GPS',
- SLEEP_MONITOR: 'SLEEP_MONITOR'
+ SLEEP_MONITOR: 'SLEEP_MONITOR',
+ SLEEP_DETECTOR: 'SLEEP_DETECTOR',
+ STRESS_MONITOR: 'STRESS_MONITOR'
};
var HumanActivityRecorderType = {
@@ -108,6 +111,10 @@ function convertActivityData(type, data) {
return new HumanActivityGPSInfoArray(gpsInfo);
case HumanActivityType.SLEEP_MONITOR:
return new HumanActivitySleepMonitorData(data);
+ case HumanActivityType.SLEEP_DETECTOR:
+ return new HumanActivitySleepDetectorData(data);
+ case HumanActivityType.STRESS_MONITOR:
+ return new HumanActivityStressMonitorData(data);
default:
utils_.error('Uknown human activity type: ' + type);
}
@@ -146,6 +153,50 @@ function convertActivityRecorderData(type, data) {
return createRecorderData(func, data);
}
+function StressMonitorDataRange(label, min, max) {
+ validator_.validateConstructorCall(this, tizen.StressMonitorDataRange);
+
+ var args = validator_.validateArgs(arguments, [
+ { name: 'label', type: types_.STRING, optional: true, nullable: false },
+ { name: 'min', type: types_.UNSIGNED_LONG, optional: true, nullable: false },
+ { name: 'max', type: types_.UNSIGNED_LONG, optional: true, nullable: false }
+ ]);
+
+ var _label = !type_.isNullOrUndefined(args.label) ? args.label : '';
+ var _min = !type_.isNullOrUndefined(args.min) ? args.min : 0;
+ var _max = !type_.isNull(args.max) ? args.max : undefined;
+
+ Object.defineProperties(this, {
+ label: {
+ get: function() {
+ return _label;
+ },
+ set: function(v) {
+ _label = !type_.isNullOrUndefined(v) ? v : _label;
+ },
+ enumerable: true
+ },
+ min: {
+ get: function() {
+ return _min;
+ },
+ set: function(v) {
+ _min = !type_.isNullOrUndefined(v) ? converter_.toUnsignedLong(v) : _min;
+ },
+ enumerable: true
+ },
+ max: {
+ get: function() {
+ return _max;
+ },
+ set: function(v) {
+ _max = !type_.isNullOrUndefined(v) ? converter_.toUnsignedLong(v) : _max;
+ },
+ enumerable: true
+ }
+ });
+}
+
function ActivityRecognitionListenerManager() {
this.listeners = {};
this.nextId = 1;
@@ -254,7 +305,7 @@ function startListener(listenerId, listener, method, data) {
}
// always set the listener
- //if it's another call to startListener() overwrite the old one
+ // if it's another call to startListener() overwrite the old one
native_.addListener(listenerId, listener);
}
@@ -306,6 +357,8 @@ function GPSCallback(result) {
}
}
+var stressListener = null;
+
HumanActivityMonitorManager.prototype.start = function(type, changedCallback) {
var args = validator_.validateArgs(arguments, [
{ name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityType) },
@@ -364,6 +417,9 @@ HumanActivityMonitorManager.prototype.start = function(type, changedCallback) {
case HumanActivityType.GPS:
listener = GPSCallback;
break;
+ case HumanActivityType.STRESS_MONITOR:
+ listener = stressMonitorListener.onListener;
+ break;
default:
listener = function(result) {
native_.callIfPossible(
@@ -387,7 +443,10 @@ HumanActivityMonitorManager.prototype.start = function(type, changedCallback) {
pedometerListener = args.changedCallback;
}
- if (HumanActivityType.GPS === args.type) {
+ if (
+ HumanActivityType.GPS === args.type ||
+ HumanActivityType.STRESS_MONITOR === args.type
+ ) {
var callback = function(result) {
if (native_.isFailure(result)) {
native_.callIfPossible(
@@ -402,7 +461,11 @@ HumanActivityMonitorManager.prototype.start = function(type, changedCallback) {
}
};
- GPSListener = callback;
+ if (HumanActivityType.GPS === args.type) {
+ GPSListener = callback;
+ } else if (HumanActivityType.STRESS_MONITOR === args.type) {
+ stressListener = callback;
+ }
}
};
@@ -439,6 +502,10 @@ HumanActivityMonitorManager.prototype.stop = function(type) {
if (HumanActivityType.GPS === args.type) {
GPSListener = null;
}
+
+ if (HumanActivityType.STRESS_MONITOR === args.type) {
+ stressListener = null;
+ }
};
HumanActivityMonitorManager.prototype.setAccumulativePedometerListener = function() {
@@ -794,6 +861,91 @@ HumanActivityMonitorManager.prototype.removeGestureRecognitionListener = functio
gestureRecognitionListener.removeListener(args.watchId);
};
+function StressMonitorListenerManager() {
+ this.listeners = {};
+ this.nextId = 1;
+}
+
+StressMonitorListenerManager.prototype.onListener = function(data) {
+ if (stressListener) {
+ stressListener(data);
+ }
+ var score = data.stressScore;
+ for (var watchId in stressMonitorListener.listeners) {
+ if (stressMonitorListener.listeners.hasOwnProperty(watchId)) {
+ var _listener = stressMonitorListener.listeners[watchId];
+ var rangeArray = _listener.ranges;
+ for (var id in rangeArray) {
+ var _min = rangeArray[id].min;
+ var _max = !type_.isUndefined(rangeArray[id].max)
+ ? rangeArray[id].max
+ : Number.MAX_VALUE;
+ if (
+ score >= _min &&
+ score < _max &&
+ (_listener.lastStressScore < _min ||
+ _listener.lastStressScore >= _max)
+ ) {
+ _listener.listener(rangeArray[id].label);
+ }
+ }
+ _listener.lastStressScore = score;
+ }
+ }
+};
+
+StressMonitorListenerManager.prototype.addListener = function(
+ ranges,
+ listener,
+ errorCallback
+) {
+ var id = this.nextId++;
+
+ this.listeners[id] = {
+ ranges: ranges,
+ listener: listener,
+ lastStressScore: -1
+ };
+
+ return id;
+};
+
+StressMonitorListenerManager.prototype.removeListener = function(watchId) {
+ if (this.listeners.hasOwnProperty(watchId)) {
+ delete this.listeners[watchId];
+ }
+};
+
+var stressMonitorListener = new StressMonitorListenerManager();
+
+HumanActivityMonitorManager.prototype.addStressMonitorChangeListener = function() {
+ utils_.checkPrivilegeAccess(privilege_.HEALTHINFO);
+ var args = validator_.validateMethod(arguments, [
+ {
+ name: 'ranges',
+ type: types_.ARRAY,
+ values: StressMonitorDataRange
+ },
+ {
+ name: 'listener',
+ type: types_.FUNCTION
+ }
+ ]);
+
+ return stressMonitorListener.addListener(args.ranges, args.listener);
+};
+
+HumanActivityMonitorManager.prototype.removeStressMonitorChangeListener = function() {
+ var args = validator_.validateMethod(arguments, [
+ {
+ name: 'watchId',
+ type: types_.LONG
+ }
+ ]);
+
+ stressMonitorListener.removeListener(args.watchId);
+};
+
function StepDifference(data) {
SetReadOnlyProperty(this, 'stepCountDifference', data.stepCountDifference);
SetReadOnlyProperty(this, 'timestamp', data.timestamp);
@@ -892,6 +1044,20 @@ function HumanActivitySleepMonitorData(data) {
HumanActivitySleepMonitorData.prototype = new HumanActivityData();
HumanActivitySleepMonitorData.prototype.constructor = HumanActivitySleepMonitorData;
+function HumanActivitySleepDetectorData(data) {
+ SetReadOnlyProperty(this, 'status', data.status);
+}
+
+HumanActivitySleepDetectorData.prototype = new HumanActivityData();
+HumanActivitySleepDetectorData.prototype.constructor = HumanActivitySleepMonitorData;
+
+function HumanActivityStressMonitorData(data) {
+ SetReadOnlyProperty(this, 'stressScore', data.stressScore);
+}
+
+HumanActivityStressMonitorData.prototype = new HumanActivityData();
+HumanActivityStressMonitorData.prototype.constructor = HumanActivityStressMonitorData;
+
//Recorded data
function HumanActivityRecorderData(data) {
if (data) {
@@ -960,4 +1126,6 @@ HumanActivityRecorderPressureData.prototype = new HumanActivityRecorderData();
HumanActivityRecorderPressureData.prototype.constructor =
HumanActivityRecorderPressureData;
+tizen.StressMonitorDataRange = StressMonitorDataRange;
+
exports = new HumanActivityMonitorManager();
diff --git a/src/humanactivitymonitor/humanactivitymonitor_extension.cc b/src/humanactivitymonitor/humanactivitymonitor_extension.cc
index 6074271e..e17fc87c 100644
--- a/src/humanactivitymonitor/humanactivitymonitor_extension.cc
+++ b/src/humanactivitymonitor/humanactivitymonitor_extension.cc
@@ -27,6 +27,9 @@ common::Extension* CreateExtension() {
HumanActivityMonitorExtension::HumanActivityMonitorExtension() {
SetExtensionName("tizen.humanactivitymonitor");
SetJavaScriptAPI(kSource_humanactivitymonitor_api);
+
+ const char* entry_points[] = {"tizen.StressMonitorDataRange", NULL};
+ SetExtraJSEntryPoints(entry_points);
}
HumanActivityMonitorExtension::~HumanActivityMonitorExtension() {
diff --git a/src/humanactivitymonitor/humanactivitymonitor_manager.cc b/src/humanactivitymonitor/humanactivitymonitor_manager.cc
index a6a7d3ae..0762f54c 100644
--- a/src/humanactivitymonitor/humanactivitymonitor_manager.cc
+++ b/src/humanactivitymonitor/humanactivitymonitor_manager.cc
@@ -48,6 +48,8 @@ const std::string kActivityTypeWristUp = "WRIST_UP";
const std::string kActivityTypeHrm = "HRM";
const std::string kActivityTypeSleepMonitor = "SLEEP_MONITOR";
const std::string kActivityTypePressure = "PRESSURE";
+const std::string kActivityTypeSleepDetector = "SLEEP_DETECTOR";
+const std::string kActivityTypeStressMonitor = "STRESS_MONITOR";
const std::string kSleepStateAwake = "AWAKE";
const std::string kSleepStateAsleep = "ASLEEP";
@@ -58,6 +60,7 @@ const std::string kSampleInterval = "sampleInterval";
const std::string kStatus = "status";
const std::string kTimestamp = "timestamp";
+const std::string kStressScore = "stressScore";
const std::string kStepStatus = "stepStatus";
const std::string kSpeed = "speed";
@@ -1480,6 +1483,53 @@ HumanActivityMonitorManager::HumanActivityMonitorManager()
return PlatformResult(ErrorCode::NO_ERROR);
};
+ auto convert_sleep_detector = [](sensor_event_s* event,
+ picojson::object* data) -> PlatformResult {
+ ScopeLogger("convert_sleep_detector");
+
+ if (event->value_count < 1) {
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "To few values of SLEEP event");
+ }
+
+ sensor_sleep_state_e state = static_cast<sensor_sleep_state_e>(event->values[0]);
+ std::string sleep_state;
+
+ switch (state) {
+ case SENSOR_SLEEP_STATE_WAKE:
+ sleep_state = kSleepStateAwake;
+ break;
+
+ case SENSOR_SLEEP_STATE_SLEEP:
+ sleep_state = kSleepStateAsleep;
+ break;
+
+ case SENSOR_SLEEP_STATE_UNKNOWN:
+ sleep_state = kSleepStateUnknown;
+ break;
+
+ default:
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown sleep state",
+ ("Unknown sleep state: %d", state));
+ }
+
+ data->insert(std::make_pair(kStatus, picojson::value(sleep_state)));
+
+ return PlatformResult(ErrorCode::NO_ERROR);
+ };
+
+ auto convert_stress = [](sensor_event_s* event, picojson::object* data) -> PlatformResult {
+ ScopeLogger("convert_stress");
+
+ if (event->value_count < 1) {
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "To few values of STRESS event");
+ }
+
+ float stress_score = event->values[0];
+ data->insert(std::make_pair(kStressScore, picojson::value(static_cast<double>(stress_score))));
+
+ return PlatformResult(ErrorCode::NO_ERROR);
+ };
+
auto convert_recorded_hrm = [](void* data, picojson::object* obj) -> PlatformResult {
ScopeLogger("Entered into asynchronous function, convert_recorded_hrm");
@@ -1527,6 +1577,14 @@ HumanActivityMonitorManager::HumanActivityMonitorManager()
std::make_pair(kActivityTypePedometer, std::make_shared<Monitor::PedometerMonitor>()));
monitors_.insert(std::make_pair(kActivityTypeWristUp,
std::make_shared<Monitor::GestureMonitor>(kActivityTypeWristUp)));
+ monitors_.insert(std::make_pair(kActivityTypeSleepDetector,
+ std::make_shared<Monitor::SensorMonitor>(
+ kActivityTypeSleepDetector, SENSOR_HUMAN_SLEEP_DETECTOR,
+ convert_sleep_detector, nullptr)));
+ monitors_.insert(std::make_pair(
+ kActivityTypeStressMonitor,
+ std::make_shared<Monitor::SensorMonitor>(
+ kActivityTypeStressMonitor, SENSOR_HUMAN_STRESS_MONITOR, convert_stress, nullptr)));
monitors_.insert(std::make_pair(
kActivityTypeHrm, std::make_shared<Monitor::SensorMonitor>(
kActivityTypeHrm, SENSOR_HRM, convert_hrm, convert_recorded_hrm)));
diff --git a/src/inputdevice/inputdevice_api.js b/src/inputdevice/inputdevice_api.js
index d349d27e..e8281980 100644
--- a/src/inputdevice/inputdevice_api.js
+++ b/src/inputdevice/inputdevice_api.js
@@ -41,8 +41,8 @@ function InputDeviceKey(dict) {
}
/**
- * This class provides access to the API functionalities
- * through the tizen.tvinputdevice interface.
+ * This class provides access to the API functionalities through the
+ * tizen.tvinputdevice interface.
* @constructor
*/
function InputDeviceManager() {
@@ -87,8 +87,8 @@ InputDeviceManager.prototype.getKey = function(keyName) {
};
/**
- * Registers an input device key to receive DOM keyboard event
- * when it is pressed or released.
+ * Registers an input device key to receive DOM keyboard event when it is pressed or
+ * released.
* @param {!string} keyName The key name
*/
InputDeviceManager.prototype.registerKey = function(keyName) {
diff --git a/src/iotcon/iotcon_instance.cc b/src/iotcon/iotcon_instance.cc
index 6bc88a8f..3eee1479 100644
--- a/src/iotcon/iotcon_instance.cc
+++ b/src/iotcon/iotcon_instance.cc
@@ -1814,6 +1814,8 @@ common::TizenResult IotconInstance::Initialize(const picojson::object& args) {
std::string realPath =
common::FilesystemProvider::Create().GetRealPath(filePath.get<std::string>());
+ CHECK_STORAGE_ACCESS_AND_RETURN(realPath);
+
auto result = IotconUtils::ConvertIotconError(iotcon_initialize(realPath.c_str()));
if (!result) {
LogAndReturnTizenError(result);
diff --git a/src/mediacontroller/mediacontroller_api.js b/src/mediacontroller/mediacontroller_api.js
index be155e55..9a2c6df0 100755
--- a/src/mediacontroller/mediacontroller_api.js
+++ b/src/mediacontroller/mediacontroller_api.js
@@ -32,6 +32,7 @@ function ListenerManager(native, listenerName, handle) {
this.native = native;
this.listenerName = listenerName;
this.handle = handle || function(msg, listener, watchId) {};
+ this.requestIdToListenerId = {};
}
ListenerManager.prototype.addListener = function(callback) {
@@ -124,7 +125,7 @@ var ServerCommandListener = new ListenerManager(
var nativeData = {
clientName: msg.clientName,
- replyId: msg.replyId,
+ requestId: msg.requestId,
data: data
};
@@ -140,12 +141,12 @@ var ReplyCommandListener = new ListenerManager(native_, '_ReplyCommandListener',
listener,
watchId
) {
- if (msg.replyId === watchId) {
- listener(msg.data);
+ if (this.requestIdToListenerId[watchId] === msg.requestId) {
+ listener(msg);
this.removeListener(watchId);
+ delete this.requestIdToListenerId[watchId];
return true;
}
-
return false;
});
@@ -224,6 +225,14 @@ var MediaControllerPlaybackState = {
REWIND: 'REWIND'
};
+var MediaControllerContentType = {
+ IMAGE: 'IMAGE',
+ MUSIC: 'MUSIC',
+ VIDEO: 'VIDEO',
+ OTHER: 'OTHER',
+ UNDECIDED: 'UNDECIDED'
+};
+
function MediaControllerManager() {}
MediaControllerManager.prototype.getClient = function() {
@@ -845,25 +854,28 @@ MediaControllerServerInfo.prototype.sendCommand = function(
{ name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
]);
- var nativeData = {
- command: args.command,
- data: args.data,
- name: this.name
- };
-
- var replyId = ReplyCommandListener.addListener(successCallback);
-
- nativeData.replyId = replyId;
- nativeData.listenerId = ReplyCommandListener.listenerName;
var callback = function(result) {
if (native_.isFailure(result)) {
native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
return;
}
- args.successCallback(native_.getResultObject(result));
+ native_.callIfPossible(
+ args.successCallback,
+ native_.getResultObject(result).data
+ );
};
- native_.call('MediaControllerServerInfo_sendCommand', nativeData, callback);
+ var nativeData = {
+ command: args.command,
+ data: args.data,
+ name: this.name,
+ listenerId: ReplyCommandListener.listenerName
+ };
+
+ var replyListenerId = ReplyCommandListener.addListener(callback);
+ var result = native_.callSync('MediaControllerServerInfo_sendCommand', nativeData);
+
+ ReplyCommandListener.requestIdToListenerId[replyListenerId] = result.requestId;
};
MediaControllerServerInfo.prototype.addServerStatusChangeListener = function(listener) {
diff --git a/src/mediacontroller/mediacontroller_client.cc b/src/mediacontroller/mediacontroller_client.cc
index cce90a29..05effb8c 100644
--- a/src/mediacontroller/mediacontroller_client.cc
+++ b/src/mediacontroller/mediacontroller_client.cc
@@ -22,6 +22,7 @@
#include "common/logger.h"
#include "common/scope_exit.h"
+#include "common/tools.h"
#include "mediacontroller/mediacontroller_types.h"
@@ -30,6 +31,8 @@ namespace mediacontroller {
using common::PlatformResult;
using common::ErrorCode;
+using common::tools::ReportError;
+using common::tools::ReportSuccess;
MediaControllerClient::MediaControllerClient() : handle_(nullptr) {
ScopeLogger();
@@ -38,6 +41,12 @@ MediaControllerClient::MediaControllerClient() : handle_(nullptr) {
MediaControllerClient::~MediaControllerClient() {
ScopeLogger();
+ int ret = mc_client_unset_cmd_reply_received_cb(handle_);
+ if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+ LoggerE("Failed to unset cmd reply callback. Error code: %d; Error message: %s",
+ ret, get_error_message(ret));
+ }
+
if (nullptr != server_status_listener_ && !UnsetServerStatusChangeListener()) {
LoggerE("Failed to unset server status change listener");
}
@@ -60,6 +69,13 @@ PlatformResult MediaControllerClient::Init() {
("mc_client_create() error: %d, message: %s", ret, get_error_message(ret)));
}
+ ret = mc_client_set_cmd_reply_received_cb(handle_, OnCommandReply, this);
+ if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+ return LogAndCreateResult(
+ ErrorCode::UNKNOWN_ERR, "Unable to register cmd reply received callback",
+ ("mc_client_set_cmd_reply_received_cb() error: %d, message: %s", ret, get_error_message(ret)));
+ }
+
return PlatformResult(ErrorCode::NO_ERROR);
}
@@ -138,10 +154,9 @@ PlatformResult MediaControllerClient::GetLatestServerInfo(picojson::value* serve
}
std::string state_str;
- PlatformResult result = Types::PlatformEnumToString(Types::kMediaControllerServerState,
- static_cast<int>(state), &state_str);
+ PlatformResult result = types::MediaControllerServerStateEnum.getName(state, &state_str);
if (!result) {
- LoggerE("PlatformEnumToString failed, error: %s", result.message().c_str());
+ LoggerE("MediaControllerServerStateEnum.getName() failed, error: %s", result.message().c_str());
return result;
}
@@ -172,7 +187,7 @@ PlatformResult MediaControllerClient::GetPlaybackInfo(const std::string& server_
// playback state
std::string state;
- PlatformResult result = Types::ConvertPlaybackState(playback_h, &state);
+ PlatformResult result = types::ConvertPlaybackState(playback_h, &state);
if (!result) {
LoggerE("ConvertPlaybackState failed, error: %s", result.message().c_str());
return result;
@@ -180,7 +195,7 @@ PlatformResult MediaControllerClient::GetPlaybackInfo(const std::string& server_
// playback position
double position;
- result = Types::ConvertPlaybackPosition(playback_h, &position);
+ result = types::ConvertPlaybackPosition(playback_h, &position);
if (!result) {
LoggerE("ConvertPlaybackPosition failed, error: %s", result.message().c_str());
return result;
@@ -226,7 +241,7 @@ PlatformResult MediaControllerClient::GetMetadata(const std::string& server_name
ScopeLogger();
int ret;
- mc_metadata_h metadata_h;
+ mc_metadata_h metadata_h = nullptr;
ret = mc_client_get_server_metadata(handle_, server_name.c_str(), &metadata_h);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(
@@ -235,10 +250,10 @@ PlatformResult MediaControllerClient::GetMetadata(const std::string& server_name
}
SCOPE_EXIT {
- mc_client_destroy_metadata(metadata_h);
+ mc_metadata_destroy(metadata_h);
};
- PlatformResult result = Types::ConvertMetadata(metadata_h, metadata);
+ PlatformResult result = types::ConvertMetadata(metadata_h, metadata);
if (!result) {
return result;
}
@@ -249,11 +264,11 @@ PlatformResult MediaControllerClient::GetMetadata(const std::string& server_name
PlatformResult MediaControllerClient::SetServerStatusChangeListener(const JsonCallback& callback) {
ScopeLogger();
- int ret = mc_client_set_server_update_cb(handle_, OnServerStatusUpdate, this);
+ int ret = mc_client_set_server_updated_cb(handle_, OnServerStatusUpdate, this);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Unable to set server status listener",
- ("mc_client_set_server_update_cb() error: %d, message: %s", ret, get_error_message(ret)));
+ ("mc_client_set_server_updated_cb() error: %d, message: %s", ret, get_error_message(ret)));
}
server_status_listener_ = callback;
@@ -263,11 +278,11 @@ PlatformResult MediaControllerClient::SetServerStatusChangeListener(const JsonCa
PlatformResult MediaControllerClient::UnsetServerStatusChangeListener() {
ScopeLogger();
- int ret = mc_client_unset_server_update_cb(handle_);
+ int ret = mc_client_unset_server_updated_cb(handle_);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
- return LogAndCreateResult(
- ErrorCode::UNKNOWN_ERR, "Unable to unset server status listener",
- ("mc_client_unset_server_update_cb() error: %d, message: %s", ret, get_error_message(ret)));
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to unset server status listener",
+ ("mc_client_unset_server_updated_cb() error: %d, message: %s", ret,
+ get_error_message(ret)));
}
server_status_listener_ = nullptr;
return PlatformResult(ErrorCode::NO_ERROR);
@@ -280,10 +295,9 @@ void MediaControllerClient::OnServerStatusUpdate(const char* server_name, mc_ser
// server state
std::string state_str;
- PlatformResult result = Types::PlatformEnumToString(Types::kMediaControllerServerState,
- static_cast<int>(state), &state_str);
+ PlatformResult result = types::MediaControllerServerStateEnum.getName(state, &state_str);
if (!result) {
- LoggerE("PlatformEnumToString failed, error: %s", result.message().c_str());
+ LoggerE("MediaControllerServerStateEnum.getName() failed, error: %s", result.message().c_str());
return;
}
@@ -305,9 +319,9 @@ PlatformResult MediaControllerClient::SetPlaybackInfoListener(const JsonCallback
// The purpose of this lambda is to unset as many setters as we can in case of failure.
int (*unsetters[])(mc_client_h) = {
- mc_client_unset_playback_update_cb, mc_client_unset_shuffle_mode_update_cb,
- mc_client_unset_repeat_mode_update_cb,
- /*mc_client_unset_metadata_update_cb the last unsetter will never be used*/};
+ mc_client_unset_playback_updated_cb, mc_client_unset_shuffle_mode_updated_cb,
+ mc_client_unset_repeat_mode_updated_cb,
+ /*mc_client_unset_metadata_updated_cb the last unsetter will never be used*/};
// This loop is no-op in case of success.
for (int i = 0; i < failed_setter; ++i) {
@@ -318,35 +332,35 @@ PlatformResult MediaControllerClient::SetPlaybackInfoListener(const JsonCallback
}
};
- int ret = mc_client_set_playback_update_cb(handle_, OnPlaybackUpdate, this);
+ int ret = mc_client_set_playback_updated_cb(handle_, OnPlaybackUpdate, this);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
- return LogAndCreateResult(
- ErrorCode::UNKNOWN_ERR, "Unable to register playback listener",
- ("mc_client_set_playback_update_cb() error: %d, message: %s", ret, get_error_message(ret)));
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to register playback listener",
+ ("mc_client_set_playback_updated_cb() error: %d, message: %s", ret,
+ get_error_message(ret)));
}
- ret = mc_client_set_shuffle_mode_update_cb(handle_, OnShuffleModeUpdate, this);
+ ret = mc_client_set_shuffle_mode_updated_cb(handle_, OnShuffleModeUpdate, this);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
failed_setter = 1;
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to register shuffle mode listener",
- ("mc_client_set_shuffle_mode_update_cb() error: %d, message: %s", ret,
- get_error_message(ret)));
+ ("mc_client_set_shuffle_mode_updated_cb() error: %d, message: %s",
+ ret, get_error_message(ret)));
}
- ret = mc_client_set_repeat_mode_update_cb(handle_, OnRepeatModeUpdate, this);
+ ret = mc_client_set_repeat_mode_updated_cb(handle_, OnRepeatModeUpdate, this);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
failed_setter = 2;
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to register repeat mode listener",
- ("mc_client_set_repeat_mode_update_cb() error: %d, message: %s", ret,
+ ("mc_client_set_repeat_mode_updated_cb() error: %d, message: %s", ret,
get_error_message(ret)));
}
- ret = mc_client_set_metadata_update_cb(handle_, OnMetadataUpdate, this);
+ ret = mc_client_set_metadata_updated_cb(handle_, OnMetadataUpdate, this);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
failed_setter = 3;
- return LogAndCreateResult(
- ErrorCode::UNKNOWN_ERR, "Unable to register metadata listener",
- ("mc_client_set_metadata_update_cb() error: %d, message: %s", ret, get_error_message(ret)));
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to register metadata listener",
+ ("mc_client_set_metadata_updated_cb() error: %d, message: %s", ret,
+ get_error_message(ret)));
}
playback_info_listener_ = callback;
@@ -360,10 +374,10 @@ PlatformResult MediaControllerClient::UnsetPlaybackInfoListener() {
// In the Javascript layer, the removePlaybackInfoChangeListener() method always succeeds, so we
// do not need to catch the returned value.
- mc_client_unset_playback_update_cb(handle_);
- mc_client_unset_shuffle_mode_update_cb(handle_);
- mc_client_unset_repeat_mode_update_cb(handle_);
- mc_client_unset_metadata_update_cb(handle_);
+ mc_client_unset_playback_updated_cb(handle_);
+ mc_client_unset_shuffle_mode_updated_cb(handle_);
+ mc_client_unset_repeat_mode_updated_cb(handle_);
+ mc_client_unset_metadata_updated_cb(handle_);
playback_info_listener_ = nullptr;
@@ -377,7 +391,7 @@ void MediaControllerClient::OnPlaybackUpdate(const char* server_name, mc_playbac
// playback state
std::string state;
- PlatformResult result = Types::ConvertPlaybackState(playback, &state);
+ PlatformResult result = types::ConvertPlaybackState(playback, &state);
if (!result) {
LoggerE("ConvertPlaybackState failed, error: %s", result.message().c_str());
return;
@@ -385,7 +399,7 @@ void MediaControllerClient::OnPlaybackUpdate(const char* server_name, mc_playbac
// playback position
double position;
- result = Types::ConvertPlaybackPosition(playback, &position);
+ result = types::ConvertPlaybackPosition(playback, &position);
if (!result) {
LoggerE("ConvertPlaybackPosition failed, error: %s", result.message().c_str());
return;
@@ -441,7 +455,7 @@ void MediaControllerClient::OnMetadataUpdate(const char* server_name, mc_metadat
picojson::object& data_o = data.get<picojson::object>();
picojson::value metadata = picojson::value(picojson::object());
- PlatformResult result = Types::ConvertMetadata(metadata_h, &metadata.get<picojson::object>());
+ PlatformResult result = types::ConvertMetadata(metadata_h, &metadata.get<picojson::object>());
if (!result) {
LoggerE("ConvertMetadata failed, error: %s", result.message().c_str());
return;
@@ -457,8 +471,8 @@ void MediaControllerClient::OnMetadataUpdate(const char* server_name, mc_metadat
PlatformResult MediaControllerClient::SendCommand(const std::string& server_name,
const std::string& command,
const picojson::value& data,
- const std::string& reply_id,
- const JsonCallback& reply_cb) {
+ const JsonCallback& reply_cb,
+ char** request_id) {
ScopeLogger();
bundle* bundle = bundle_create();
SCOPE_EXIT {
@@ -466,13 +480,6 @@ PlatformResult MediaControllerClient::SendCommand(const std::string& server_name
};
int ret;
- ret = bundle_add(bundle, "replyId", reply_id.c_str());
- if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
- return LogAndCreateResult(
- ErrorCode::UNKNOWN_ERR, "Unable to add replyId to bundle",
- ("bundle_add(replyId) error: %d, message: %s", ret, get_error_message(ret)));
- }
-
ret = bundle_add(bundle, "data", data.serialize().c_str());
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(
@@ -480,12 +487,11 @@ PlatformResult MediaControllerClient::SendCommand(const std::string& server_name
("bundle_add(data) error: %d, message: %s", ret, get_error_message(ret)));
}
- ret = mc_client_send_custom_command(handle_, server_name.c_str(), command.c_str(), bundle,
- OnCommandReply, this);
+ ret = mc_client_send_custom_cmd(handle_, server_name.c_str(), command.c_str(), bundle, request_id);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Error sending custom command",
- ("mc_client_send_custom_command() error: %d, message: %s", ret, get_error_message(ret)));
+ ("mc_client_send_custom_cmd() error: %d, message: %s", ret, get_error_message(ret)));
}
command_reply_callback_ = reply_cb;
@@ -493,66 +499,73 @@ PlatformResult MediaControllerClient::SendCommand(const std::string& server_name
return PlatformResult(ErrorCode::NO_ERROR);
}
-void MediaControllerClient::OnCommandReply(const char* server_name, int result_code, bundle* bundle,
- void* user_data) {
+void MediaControllerClient::OnCommandReply(const char* server_name, const char* request_id,
+ int result_code, bundle* bundle, void* user_data) {
ScopeLogger();
MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
+ picojson::value out = picojson::value(picojson::object());
+ picojson::object& out_o = out.get<picojson::object>();
picojson::value reply = picojson::value(picojson::object());
picojson::object& reply_o = reply.get<picojson::object>();
int ret;
- char* reply_id_str = nullptr;
char* data_str = nullptr;
SCOPE_EXIT {
- free(reply_id_str);
free(data_str);
};
-
- ret = bundle_get_str(bundle, "replyId", &reply_id_str);
- if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
- LoggerE("bundle_get_str(replyId) failed, error: %d", ret);
- return;
- }
-
- reply_o["replyId"] = picojson::value(std::string(reply_id_str));
+ picojson::value data;
ret = bundle_get_str(bundle, "data", &data_str);
- if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+ if (BUNDLE_ERROR_NONE != ret || nullptr == data_str) {
LoggerE("bundle_get_str(data) failed, error: %d", ret);
- return;
+ } else {
+ std::string err;
+ picojson::parse(data, data_str, data_str + strlen(data_str), &err);
+ if (!err.empty()) {
+ LoggerE("Failed to parse bundle data: %s", err.c_str());
+ ReportError(out_o);
+ client->command_reply_callback_(&out);
+ return;
+ }
}
- picojson::value data;
- std::string err;
- picojson::parse(data, data_str, data_str + strlen(data_str), &err);
- if (!err.empty()) {
- LoggerE("Failed to parse bundle data: %s", err.c_str());
- return;
- }
reply_o["data"] = data;
reply_o["name"] = picojson::value(server_name);
- client->command_reply_callback_(&reply);
+ if (nullptr == request_id) {
+ LoggerE("Request id is null.");
+ ReportError(out_o);
+ client->command_reply_callback_(&out);
+ return;
+ }
+ out_o["requestId"] = picojson::value(std::string(request_id));
+
+ ReportSuccess(reply, out_o);
+ client->command_reply_callback_(&out);
}
PlatformResult MediaControllerClient::SendPlaybackState(const std::string& server_name,
const std::string& state) {
ScopeLogger();
- int state_e;
- PlatformResult result =
- Types::StringToPlatformEnum(Types::kMediaControllerPlaybackState, state, &state_e);
+ // In Native API, since Tizen 5.0 an action instead of a state is sent to change the state of a
+ // server. In Web API the names were not refactored.
+ mc_playback_action_e action_e;
+ PlatformResult result = types::MediaControllerPlaybackActionEnum.getValue(state, &action_e);
if (!result) {
return result;
}
- int ret;
- ret = mc_client_send_playback_state_command(handle_, server_name.c_str(),
- static_cast<mc_playback_states_e>(state_e));
+ /* TODO: Prepare an ACR and propose use case for request_id.
+ char* request_id = nullptr;
+ SCOPE_EXIT {
+ free(request_id);
+ };*/
+ int ret = mc_client_send_playback_action_cmd(handle_, server_name.c_str(), action_e, nullptr);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error sending playback state",
- ("mc_client_send_playback_state_command() error: %d, message: %s",
- ret, get_error_message(ret)));
+ ("mc_client_send_playback_action_cmd() error: %d, message: %s", ret,
+ get_error_message(ret)));
}
return PlatformResult(ErrorCode::NO_ERROR);
diff --git a/src/mediacontroller/mediacontroller_client.h b/src/mediacontroller/mediacontroller_client.h
index bb7cb8a1..e0e669d0 100644
--- a/src/mediacontroller/mediacontroller_client.h
+++ b/src/mediacontroller/mediacontroller_client.h
@@ -46,8 +46,8 @@ class MediaControllerClient {
common::PlatformResult SendRepeatMode(const std::string& server_name, bool mode);
common::PlatformResult SendCommand(const std::string& server_name, const std::string& command,
- const picojson::value& data, const std::string& reply_id,
- const JsonCallback& reply_cb);
+ const picojson::value& data, const JsonCallback& reply_cb,
+ char** request_id);
common::PlatformResult SetServerStatusChangeListener(const JsonCallback& callback);
common::PlatformResult UnsetServerStatusChangeListener();
@@ -66,8 +66,8 @@ class MediaControllerClient {
static void OnServerStatusUpdate(const char* server_name, mc_server_state_e state,
void* user_data);
- static void OnCommandReply(const char* server_name, int result_code, bundle* bundle,
- void* user_data);
+ static void OnCommandReply(const char* server_name, const char* request_id,
+ int result_code, bundle* bundle, void* user_data);
static void OnPlaybackUpdate(const char* server_name, mc_playback_h playback, void* user_data);
static void OnShuffleModeUpdate(const char* server_name, mc_shuffle_mode_e mode, void* user_data);
static void OnRepeatModeUpdate(const char* server_name, mc_repeat_mode_e mode, void* user_data);
diff --git a/src/mediacontroller/mediacontroller_instance.cc b/src/mediacontroller/mediacontroller_instance.cc
index 350c4d69..ab7d8aa7 100644
--- a/src/mediacontroller/mediacontroller_instance.cc
+++ b/src/mediacontroller/mediacontroller_instance.cc
@@ -21,6 +21,7 @@
#include "common/platform_result.h"
#include "common/task-queue.h"
#include "common/tools.h"
+#include "common/scope_exit.h"
#include "mediacontroller/mediacontroller_types.h"
@@ -134,7 +135,7 @@ void MediaControllerInstance::MediaControllerServerUpdatePlaybackState(const pic
CHECK_EXIST(args, "state", out)
if (!server_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Server not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: server_"));
return;
}
@@ -153,7 +154,7 @@ void MediaControllerInstance::MediaControllerServerUpdatePlaybackPosition(
const picojson::value& args, picojson::object& out) {
ScopeLogger();
if (!server_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Server not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: server_"));
return;
}
@@ -174,7 +175,7 @@ void MediaControllerInstance::MediaControllerServerUpdateShuffleMode(const picoj
picojson::object& out) {
ScopeLogger();
if (!server_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Server not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: server_"));
return;
}
@@ -197,7 +198,7 @@ void MediaControllerInstance::MediaControllerServerUpdateRepeatMode(const picojs
ScopeLogger();
if (!server_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Server not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: server_"));
return;
}
@@ -219,7 +220,7 @@ void MediaControllerInstance::MediaControllerServerUpdateMetadata(const picojson
picojson::object& out) {
ScopeLogger();
if (!server_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Server not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: server_"));
return;
}
@@ -241,7 +242,7 @@ void MediaControllerInstance::MediaControllerServerAddChangeRequestPlaybackInfoL
const picojson::value& args, picojson::object& out) {
ScopeLogger();
if (!server_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Server not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: server_"));
return;
}
@@ -272,7 +273,7 @@ void MediaControllerInstance::MediaControllerServerRemoveChangeRequestPlaybackIn
const picojson::value& args, picojson::object& out) {
ScopeLogger();
if (!server_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Server not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: server_"));
return;
}
@@ -287,7 +288,7 @@ void MediaControllerInstance::MediaControllerServerAddCommandListener(const pico
picojson::object& out) {
ScopeLogger();
if (!server_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Server not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: server_"));
return;
}
@@ -311,17 +312,24 @@ void MediaControllerInstance::MediaControllerServerReplyCommand(const picojson::
picojson::object& out) {
ScopeLogger();
if (!server_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Server not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: server_"));
return;
}
CHECK_EXIST(args, "clientName", out)
- CHECK_EXIST(args, "replyId", out)
+ CHECK_EXIST(args, "requestId", out)
CHECK_EXIST(args, "data", out)
- server_->CommandReply(args.get("clientName").get<std::string>(), args.get("replyId").to_str(),
- args.get("data"));
+ auto result = server_->CommandReply(
+ args.get("clientName").get<std::string>(),
+ args.get("requestId").get<std::string>(),
+ args.get("data"));
+
+ if (!result) {
+ LogAndReportError(result, &out);
+ return;
+ }
ReportSuccess(out);
}
@@ -330,7 +338,7 @@ void MediaControllerInstance::MediaControllerServerRemoveCommandListener(
const picojson::value& args, picojson::object& out) {
ScopeLogger();
if (!server_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Server not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: server_"));
return;
}
@@ -368,7 +376,7 @@ void MediaControllerInstance::MediaControllerClientFindServers(const picojson::v
picojson::object& out) {
ScopeLogger();
if (!client_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Client not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: client_"));
return;
}
@@ -401,7 +409,7 @@ void MediaControllerInstance::MediaControllerClientGetLatestServerInfo(const pic
picojson::object& out) {
ScopeLogger();
if (!client_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Client not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: client_"));
return;
}
@@ -420,7 +428,7 @@ void MediaControllerInstance::MediaControllerClientGetPlaybackInfo(const picojso
picojson::object& out) {
ScopeLogger();
if (!client_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Client not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: client_"));
return;
}
@@ -443,7 +451,7 @@ void MediaControllerInstance::MediaControllerServerInfoSendPlaybackState(
const picojson::value& args, picojson::object& out) {
ScopeLogger();
if (!client_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Client not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: client_"));
return;
}
@@ -478,7 +486,7 @@ void MediaControllerInstance::MediaControllerServerInfoSendPlaybackPosition(
const picojson::value& args, picojson::object& out) {
ScopeLogger();
if (!client_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Client not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: client_"));
return;
}
@@ -514,7 +522,7 @@ void MediaControllerInstance::MediaControllerServerInfoSendShuffleMode(const pic
ScopeLogger();
if (!client_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Client not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: client_"));
return;
}
@@ -549,7 +557,7 @@ void MediaControllerInstance::MediaControllerServerInfoSendRepeatMode(const pico
picojson::object& out) {
ScopeLogger();
if (!client_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Client not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: client_"));
return;
}
@@ -584,31 +592,37 @@ void MediaControllerInstance::MediaControllerServerInfoSendCommand(const picojso
picojson::object& out) {
ScopeLogger();
if (!client_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Client not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: client_"));
return;
}
CHECK_EXIST(args, "listenerId", out)
- CHECK_EXIST(args, "replyId", out)
CHECK_EXIST(args, "name", out)
CHECK_EXIST(args, "command", out)
CHECK_EXIST(args, "data", out)
JsonCallback reply_cb = [this, args](picojson::value* reply) -> void {
picojson::object& reply_obj = reply->get<picojson::object>();
-
reply_obj["listenerId"] = args.get("listenerId");
-
Instance::PostMessage(this, reply->serialize().c_str());
};
+ char* request_id = nullptr;
+ SCOPE_EXIT {
+ free(request_id);
+ };
+
PlatformResult result = client_->SendCommand(
- args.get("name").get<std::string>(), args.get("command").get<std::string>(), args.get("data"),
- args.get("replyId").to_str(), reply_cb);
+ args.get("name").get<std::string>(),
+ args.get("command").get<std::string>(),
+ args.get("data"),
+ reply_cb,
+ &request_id);
if (result) {
ReportSuccess(out);
+ out["requestId"] = picojson::value(std::string(request_id));
} else {
LogAndReportError(result, &out, ("Failed to send command."));
}
@@ -618,7 +632,7 @@ void MediaControllerInstance::MediaControllerServerInfoAddServerStatusChangeList
const picojson::value& args, picojson::object& out) {
ScopeLogger();
if (!client_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Client not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: client_"));
return;
}
@@ -649,7 +663,7 @@ void MediaControllerInstance::MediaControllerServerInfoRemoveServerStatusChangeL
const picojson::value& args, picojson::object& out) {
ScopeLogger();
if (!client_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Client not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: client_"));
return;
}
@@ -664,7 +678,7 @@ void MediaControllerInstance::MediaControllerServerInfoAddPlaybackInfoChangeList
const picojson::value& args, picojson::object& out) {
ScopeLogger();
if (!client_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Client not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: client_"));
return;
}
@@ -694,7 +708,7 @@ void MediaControllerInstance::MediaControllerServerInfoAddPlaybackInfoChangeList
void MediaControllerInstance::MediaControllerServerInfoRemovePlaybackInfoChangeListener(
const picojson::value& args, picojson::object& out) {
if (!client_) {
- LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Client not initialized."), &out,
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
("Failed: client_"));
return;
}
diff --git a/src/mediacontroller/mediacontroller_server.cc b/src/mediacontroller/mediacontroller_server.cc
index b2a3e83e..dc82787b 100644
--- a/src/mediacontroller/mediacontroller_server.cc
+++ b/src/mediacontroller/mediacontroller_server.cc
@@ -74,27 +74,25 @@ PlatformResult MediaControllerServer::Init() {
PlatformResult MediaControllerServer::SetPlaybackState(const std::string& state) {
ScopeLogger();
- int state_int;
- PlatformResult result =
- Types::StringToPlatformEnum(Types::kMediaControllerPlaybackState, state, &state_int);
-
+ mc_playback_states_e state_e;
+ PlatformResult result = types::MediaControllerPlaybackStateEnum.getValue(state, &state_e);
if (!result) {
return result;
}
- if (static_cast<mc_playback_states_e>(state_int) == playback_state_) {
+ if (state_e == playback_state_) {
LoggerD("No change in playback state requested, skipping");
return PlatformResult(ErrorCode::NO_ERROR);
}
- int ret = mc_server_set_playback_state(handle_, static_cast<mc_playback_states_e>(state_int));
+ int ret = mc_server_set_playback_state(handle_, state_e);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Error setting playback state",
("mc_server_set_playback_state() error: %d, message: %s", ret, get_error_message(ret)));
}
- playback_state_ = static_cast<mc_playback_states_e>(state_int);
+ playback_state_ = state_e;
ret = mc_server_update_playback_info(handle_);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
@@ -180,16 +178,14 @@ PlatformResult MediaControllerServer::SetRepeatMode(bool mode) {
PlatformResult MediaControllerServer::SetMetadata(const picojson::object& metadata) {
ScopeLogger();
- int attribute_int, ret;
for (picojson::object::const_iterator i = metadata.begin(); i != metadata.end(); ++i) {
- PlatformResult result = Types::StringToPlatformEnum(Types::kMediaControllerMetadataAttribute,
- i->first, &attribute_int);
+ mc_meta_e attr_e;
+ PlatformResult result = types::MediaControllerMetadataAttributeEnum.getValue(i->first, &attr_e);
if (!result) {
return result;
}
- ret = mc_server_set_metadata(handle_, static_cast<mc_meta_e>(attribute_int),
- i->second.to_str().c_str());
+ int ret = mc_server_set_metadata(handle_, attr_e, i->second.to_str().c_str());
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error setting metadata",
("mc_server_set_metadata(%s) error: %d, message: %s",
@@ -197,7 +193,7 @@ PlatformResult MediaControllerServer::SetMetadata(const picojson::object& metada
}
}
- ret = mc_server_update_metadata(handle_);
+ int ret = mc_server_update_metadata(handle_);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Error updating metadata",
@@ -207,38 +203,29 @@ PlatformResult MediaControllerServer::SetMetadata(const picojson::object& metada
return PlatformResult(ErrorCode::NO_ERROR);
}
-void MediaControllerServer::OnCommandReceived(const char* client_name, const char* command,
- bundle* bundle, void* user_data) {
+void MediaControllerServer::OnCommandReceived(const char* client_name, const char* request_id,
+ const char* command, bundle* bundle, void* user_data) {
ScopeLogger();
MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
int ret;
char* data_str = nullptr;
- char* reply_id_str = nullptr;
SCOPE_EXIT {
free(data_str);
- free(reply_id_str);
};
+ picojson::value data;
ret = bundle_get_str(bundle, "data", &data_str);
- if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+ if (BUNDLE_ERROR_NONE != ret || nullptr == data_str) {
LoggerE("bundle_get_str(data) failed, error: %d", ret);
- return;
- }
-
- ret = bundle_get_str(bundle, "replyId", &reply_id_str);
- if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
- LoggerE("bundle_get_str(replyId) failed, error: %d", ret);
- return;
- }
-
- picojson::value data;
- std::string err;
- picojson::parse(data, data_str, data_str + strlen(data_str), &err);
- if (!err.empty()) {
- LoggerE("Failed to parse bundle data: %s", err.c_str());
- return;
+ } else {
+ std::string err;
+ picojson::parse(data, data_str, data_str + strlen(data_str), &err);
+ if (!err.empty()) {
+ LoggerE("Failed to parse bundle data: %s", err.c_str());
+ return;
+ }
}
picojson::value request = picojson::value(picojson::object());
@@ -246,14 +233,14 @@ void MediaControllerServer::OnCommandReceived(const char* client_name, const cha
request_o["clientName"] = picojson::value(std::string(client_name));
request_o["command"] = picojson::value(std::string(command));
- request_o["replyId"] = picojson::value(std::string(reply_id_str));
+ request_o["requestId"] = picojson::value(std::string(request_id));
request_o["data"] = data;
server->command_listener_(&request);
}
PlatformResult MediaControllerServer::CommandReply(const std::string& client_name,
- const std::string& reply_id,
+ const std::string& request_id,
const picojson::value& data) {
ScopeLogger();
@@ -264,13 +251,6 @@ PlatformResult MediaControllerServer::CommandReply(const std::string& client_nam
bundle_free(bundle);
};
- ret = bundle_add(bundle, "replyId", reply_id.c_str());
- if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
- return LogAndCreateResult(
- ErrorCode::UNKNOWN_ERR, "Unable to add replyId to bundle",
- ("bundle_add(replyId) error: %d, message: %s", ret, get_error_message(ret)));
- }
-
ret = bundle_add(bundle, "data", data.serialize().c_str());
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(
@@ -278,11 +258,11 @@ PlatformResult MediaControllerServer::CommandReply(const std::string& client_nam
("bundle_add(data) error: %d, message: %s", ret, get_error_message(ret)));
}
- ret = mc_server_send_command_reply(handle_, client_name.c_str(), 0, bundle);
+ ret = mc_server_send_cmd_reply(handle_, client_name.c_str(), request_id.c_str(), 0, bundle);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Error sending command reply",
- ("mc_server_send_command_reply() error: %d, message: %s", ret, get_error_message(ret)));
+ ("mc_server_send_cmd_reply() error: %d, message: %s", ret, get_error_message(ret)));
}
return PlatformResult(ErrorCode::NO_ERROR);
@@ -291,10 +271,10 @@ PlatformResult MediaControllerServer::CommandReply(const std::string& client_nam
PlatformResult MediaControllerServer::SetCommandListener(const JsonCallback& callback) {
ScopeLogger();
- int ret = mc_server_set_custom_command_received_cb(handle_, OnCommandReceived, this);
+ int ret = mc_server_set_custom_cmd_received_cb(handle_, OnCommandReceived, this);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to set command callback",
- ("mc_server_set_custom_command_received_cb() error: %d, message: %s",
+ ("mc_server_set_custom_cmd_received_cb() error: %d, message: %s",
ret, get_error_message(ret)));
}
command_listener_ = callback;
@@ -305,10 +285,10 @@ PlatformResult MediaControllerServer::SetCommandListener(const JsonCallback& cal
PlatformResult MediaControllerServer::UnsetCommandListener() {
ScopeLogger();
- int ret = mc_server_unset_custom_command_received_cb(handle_);
+ int ret = mc_server_unset_custom_cmd_received_cb(handle_);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to unset command callback",
- ("mc_server_set_custom_command_received_cb() error: %d, message: %s",
+ ("mc_server_unset_custom_cmd_received_cb() error: %d, message: %s",
ret, get_error_message(ret)));
}
command_listener_ = nullptr;
@@ -326,7 +306,7 @@ PlatformResult MediaControllerServer::SetChangeRequestPlaybackInfoListener(
// The purpose of this lambda is to unset as many setters as we can in case of failure.
int (*unsetters[])(mc_server_h) = {
- mc_server_unset_playback_state_command_received_cb,
+ mc_server_unset_playback_action_cmd_received_cb,
mc_server_unset_playback_position_cmd_received_cb,
mc_server_unset_shuffle_mode_cmd_received_cb,
/*mc_server_unset_repeat_mode_cmd_received_cb the last unsetter will never be used*/};
@@ -340,11 +320,13 @@ PlatformResult MediaControllerServer::SetChangeRequestPlaybackInfoListener(
}
};
- int ret = mc_server_set_playback_state_command_received_cb(handle_, OnPlaybackStateCommand, this);
+ // In Native API, since Tizen 5.0 an action instead of a state is sent to change the state of a
+ // server. In Web API the names were not refactored.
+ int ret = mc_server_set_playback_action_cmd_received_cb(handle_, OnPlaybackActionCommand, this);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Unable to set playback state command listener",
- ("mc_server_set_playback_state_command_received_cb() error: %d, message: %s", ret,
+ ("mc_server_set_playback_action_cmd_received_cb() error: %d, message: %s", ret,
get_error_message(ret)));
}
@@ -382,11 +364,11 @@ PlatformResult MediaControllerServer::SetChangeRequestPlaybackInfoListener(
PlatformResult MediaControllerServer::UnsetChangeRequestPlaybackInfoListener() {
ScopeLogger();
- int ret = mc_server_unset_playback_state_command_received_cb(handle_);
+ int ret = mc_server_unset_playback_action_cmd_received_cb(handle_);
if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Unable to unset playback state command listener",
- ("mc_server_unset_playback_state_command_received_cb() error: %d, message: %s", ret,
+ ("mc_server_unset_playback_action_cmd_received_cb() error: %d, message: %s", ret,
get_error_message(ret)));
}
@@ -419,22 +401,29 @@ PlatformResult MediaControllerServer::UnsetChangeRequestPlaybackInfoListener() {
return PlatformResult(ErrorCode::NO_ERROR);
}
-void MediaControllerServer::OnPlaybackStateCommand(const char* client_name,
- mc_playback_states_e state_e, void* user_data) {
+void MediaControllerServer::OnPlaybackActionCommand(const char* client_name, const char* request_id,
+ mc_playback_action_e action, void* user_data) {
ScopeLogger();
MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
- if (server->playback_state_ == state_e) {
- LoggerD("The media playback state did not change, skipping");
+ // Here, we need to convert mc_playback_action_e enum to mc_playback_states_e enum.
+ std::string action_str;
+ PlatformResult result = types::MediaControllerPlaybackActionEnum.getName(action, &action_str);
+ if (!result) {
+ LoggerW("MediaControllerPlaybackActionEnum.getName() failed, error: %s", result.message().c_str());
return;
}
- std::string state;
- PlatformResult result = Types::PlatformEnumToString(Types::kMediaControllerPlaybackState,
- static_cast<int>(state_e), &state);
+ mc_playback_states_e state_e;
+ result = types::MediaControllerPlaybackStateEnum.getValue(action_str, &state_e);
if (!result) {
- LoggerE("PlatformEnumToString failed, error: %s", result.message().c_str());
+ LoggerE("MediaControllerPlaybackStateEnum.getValue() failed, error: %s", result.message().c_str());
+ return;
+ }
+
+ if (server->playback_state_ == state_e) {
+ LoggerD("The media playback state did not change, skipping");
return;
}
@@ -442,7 +431,7 @@ void MediaControllerServer::OnPlaybackStateCommand(const char* client_name,
picojson::object& data_o = data.get<picojson::object>();
data_o["action"] = picojson::value(std::string("onplaybackstaterequest"));
- data_o["state"] = picojson::value(state);
+ data_o["state"] = picojson::value(action_str);
server->change_request_playback_info_listener_(&data);
}
diff --git a/src/mediacontroller/mediacontroller_server.h b/src/mediacontroller/mediacontroller_server.h
index 2fc1803a..010f59b0 100644
--- a/src/mediacontroller/mediacontroller_server.h
+++ b/src/mediacontroller/mediacontroller_server.h
@@ -41,7 +41,7 @@ class MediaControllerServer {
common::PlatformResult SetChangeRequestPlaybackInfoListener(const JsonCallback& callback);
common::PlatformResult UnsetChangeRequestPlaybackInfoListener();
- common::PlatformResult CommandReply(const std::string& client_name, const std::string& reply_id,
+ common::PlatformResult CommandReply(const std::string& client_name, const std::string& request_id,
const picojson::value& data);
common::PlatformResult SetCommandListener(const JsonCallback& callback);
@@ -60,8 +60,8 @@ class MediaControllerServer {
JsonCallback command_listener_;
- static void OnPlaybackStateCommand(const char* client_name, mc_playback_states_e state_e,
- void* user_data);
+ static void OnPlaybackActionCommand(const char* client_name, const char* request_id,
+ mc_playback_action_e action, void* user_data);
static void OnPlaybackPositionCommand(const char* client_name, const char* request_id,
unsigned long long position, void* user_data);
static void OnShuffleModeCommand(const char* client_name, const char* request_id,
@@ -69,8 +69,8 @@ class MediaControllerServer {
static void OnRepeatModeCommand(const char* client_name, const char* request_id,
mc_repeat_mode_e mode, void* user_data);
- static void OnCommandReceived(const char* client_name, const char* command, bundle* data,
- void* user_data);
+ static void OnCommandReceived(const char* client_name, const char* request_id,
+ const char* command, bundle* data, void* user_data);
};
} // namespace mediacontroller
diff --git a/src/mediacontroller/mediacontroller_types.cc b/src/mediacontroller/mediacontroller_types.cc
index f56c431b..4e9cde12 100644
--- a/src/mediacontroller/mediacontroller_types.cc
+++ b/src/mediacontroller/mediacontroller_types.cc
@@ -28,104 +28,77 @@ namespace mediacontroller {
using common::PlatformResult;
using common::ErrorCode;
-const std::string Types::kMediaControllerServerState = "MediaControllerServerState";
-const std::string Types::kMediaControllerPlaybackState = "MediaControllerPlaybackState";
-const std::string Types::kMediaControllerMetadataAttribute = "MediaControllerMetadataAttribute";
-
-const PlatformEnumMap Types::platform_enum_map_ = {{kMediaControllerServerState,
- {{"NONE", MC_SERVER_STATE_NONE},
- {"ACTIVE", MC_SERVER_STATE_ACTIVATE},
- {"INACTIVE", MC_SERVER_STATE_DEACTIVATE}}},
- {kMediaControllerPlaybackState,
- {{"PLAY", MC_PLAYBACK_STATE_PLAYING},
- {"PAUSE", MC_PLAYBACK_STATE_PAUSED},
- {"STOP", MC_PLAYBACK_STATE_STOPPED},
- {"NEXT", MC_PLAYBACK_STATE_NEXT_FILE},
- {"PREV", MC_PLAYBACK_STATE_PREV_FILE},
- {"FORWARD", MC_PLAYBACK_STATE_FAST_FORWARD},
- {"REWIND", MC_PLAYBACK_STATE_REWIND}}},
- {kMediaControllerMetadataAttribute,
- {{"title", MC_META_MEDIA_TITLE},
- {"artist", MC_META_MEDIA_ARTIST},
- {"album", MC_META_MEDIA_ALBUM},
- {"author", MC_META_MEDIA_AUTHOR},
- {"genre", MC_META_MEDIA_GENRE},
- {"duration", MC_META_MEDIA_DURATION},
- {"date", MC_META_MEDIA_DATE},
- {"copyright", MC_META_MEDIA_COPYRIGHT},
- {"description", MC_META_MEDIA_DESCRIPTION},
- {"trackNum", MC_META_MEDIA_TRACK_NUM},
- {"picture", MC_META_MEDIA_PICTURE}}}};
-
-PlatformEnumReverseMap Types::platform_enum_reverse_map_ = {};
-
-PlatformResult Types::GetPlatformEnumMap(const std::string& type,
- std::map<std::string, int>* enum_map) {
- ScopeLogger();
-
- auto iter = platform_enum_map_.find(type);
- if (iter == platform_enum_map_.end()) {
- return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
- std::string("Undefined platform enum type ") + type);
- }
-
- *enum_map = platform_enum_map_.at(type);
-
- return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult Types::StringToPlatformEnum(const std::string& type, const std::string& value,
- int* platform_enum) {
- ScopeLogger();
-
- std::map<std::string, int> def;
- PlatformResult result = GetPlatformEnumMap(type, &def);
- if (!result) {
- return result;
- }
-
- auto def_iter = def.find(value);
- if (def_iter != def.end()) {
- *platform_enum = def_iter->second;
- return PlatformResult(ErrorCode::NO_ERROR);
- }
-
- std::string message = "Platform enum value " + value + " not found for " + type;
- return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, message);
-}
-
-PlatformResult Types::PlatformEnumToString(const std::string& type, int value,
- std::string* platform_str) {
- ScopeLogger();
-
- if (platform_enum_reverse_map_.empty()) {
- for (auto& def : platform_enum_map_) {
- platform_enum_reverse_map_[def.first] = {};
-
- for (auto& key : def.second) {
- platform_enum_reverse_map_[def.first][key.second] = key.first;
- }
- }
- }
-
- auto it = platform_enum_reverse_map_.find(type);
- if (it == platform_enum_reverse_map_.end()) {
- return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
- std::string("Undefined platform enum type ") + type);
- }
-
- auto def = platform_enum_reverse_map_.at(type);
- auto def_it = def.find(value);
- if (def_it != def.end()) {
- *platform_str = def_it->second;
- return PlatformResult(ErrorCode::NO_ERROR);
- }
-
- std::string message = "Platform enum value " + std::to_string(value) + " not found for " + type;
- return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, message);
-}
-
-PlatformResult Types::ConvertPlaybackState(mc_playback_h playback_h, std::string* state) {
+namespace types {
+
+const common::PlatformEnum<mc_server_state_e> MediaControllerServerStateEnum {
+ {"NONE", MC_SERVER_STATE_NONE},
+ {"ACTIVE", MC_SERVER_STATE_ACTIVATE},
+ {"INACTIVE", MC_SERVER_STATE_DEACTIVATE}
+};
+
+const common::PlatformEnum<mc_playback_states_e> MediaControllerPlaybackStateEnum {
+ {"PLAY", MC_PLAYBACK_STATE_PLAYING},
+ {"PAUSE", MC_PLAYBACK_STATE_PAUSED},
+ {"STOP", MC_PLAYBACK_STATE_STOPPED},
+ {"NEXT", MC_PLAYBACK_STATE_MOVING_TO_NEXT},
+ {"PREV", MC_PLAYBACK_STATE_MOVING_TO_PREVIOUS},
+ {"FORWARD", MC_PLAYBACK_STATE_FAST_FORWARDING},
+ {"REWIND", MC_PLAYBACK_STATE_REWINDING}
+};
+
+const common::PlatformEnum<mc_playback_action_e> MediaControllerPlaybackActionEnum {
+ {"PLAY", MC_PLAYBACK_ACTION_PLAY},
+ {"PAUSE", MC_PLAYBACK_ACTION_PAUSE},
+ {"STOP", MC_PLAYBACK_ACTION_STOP},
+ {"NEXT", MC_PLAYBACK_ACTION_NEXT},
+ {"PREV", MC_PLAYBACK_ACTION_PREV},
+ {"FORWARD", MC_PLAYBACK_ACTION_FAST_FORWARD},
+ {"REWIND", MC_PLAYBACK_ACTION_REWIND}
+};
+
+const common::PlatformEnum<mc_meta_e> MediaControllerMetadataAttributeEnum {
+ {"title", MC_META_MEDIA_TITLE},
+ {"artist", MC_META_MEDIA_ARTIST},
+ {"album", MC_META_MEDIA_ALBUM},
+ {"author", MC_META_MEDIA_AUTHOR},
+ {"genre", MC_META_MEDIA_GENRE},
+ {"duration", MC_META_MEDIA_DURATION},
+ {"date", MC_META_MEDIA_DATE},
+ {"copyright", MC_META_MEDIA_COPYRIGHT},
+ {"description", MC_META_MEDIA_DESCRIPTION},
+ {"trackNum", MC_META_MEDIA_TRACK_NUM},
+ {"picture", MC_META_MEDIA_PICTURE}
+};
+
+const common::PlatformEnum<mc_repeat_mode_e> MediaControllerRepeatModeEnum {
+ {"REPEAT_OFF", MC_REPEAT_MODE_OFF},
+ {"REPEAT_ONE", MC_REPEAT_MODE_ONE_MEDIA},
+ {"REPEAT_ALL", MC_REPEAT_MODE_ON}
+};
+
+const common::PlatformEnum<mc_content_age_rating_e> MediaControllerContentAgeRatingEnum {
+ {"ALL", MC_CONTENT_RATING_ALL}, {"1", MC_CONTENT_RATING_1_PLUS},
+ {"2", MC_CONTENT_RATING_2_PLUS}, {"3", MC_CONTENT_RATING_3_PLUS},
+ {"4", MC_CONTENT_RATING_4_PLUS}, {"5", MC_CONTENT_RATING_5_PLUS},
+ {"6", MC_CONTENT_RATING_6_PLUS}, {"7", MC_CONTENT_RATING_7_PLUS},
+ {"8", MC_CONTENT_RATING_8_PLUS}, {"9", MC_CONTENT_RATING_9_PLUS},
+ {"10", MC_CONTENT_RATING_10_PLUS}, {"11", MC_CONTENT_RATING_11_PLUS},
+ {"12", MC_CONTENT_RATING_12_PLUS}, {"13", MC_CONTENT_RATING_13_PLUS},
+ {"14", MC_CONTENT_RATING_14_PLUS}, {"15", MC_CONTENT_RATING_15_PLUS},
+ {"16", MC_CONTENT_RATING_16_PLUS}, {"17", MC_CONTENT_RATING_17_PLUS},
+ {"18", MC_CONTENT_RATING_18_PLUS}, {"19", MC_CONTENT_RATING_19_PLUS}
+};
+
+const common::PlatformEnum<mc_content_type_e> MediaControllerContentTypeEnum {
+ {"IMAGE", MC_CONTENT_TYPE_IMAGE},
+ {"MUSIC", MC_CONTENT_TYPE_MUSIC},
+ {"VIDEO", MC_CONTENT_TYPE_VIDEO},
+ {"OTHER", MC_CONTENT_TYPE_OTHER},
+ {"UNDECIDED", MC_CONTENT_TYPE_UNDECIDED}
+};
+
+
+PlatformResult ConvertPlaybackState(mc_playback_h playback_h, std::string* state) {
ScopeLogger();
int ret;
@@ -140,17 +113,16 @@ PlatformResult Types::ConvertPlaybackState(mc_playback_h playback_h, std::string
state_e = MC_PLAYBACK_STATE_STOPPED;
}
- PlatformResult result = Types::PlatformEnumToString(Types::kMediaControllerPlaybackState,
- static_cast<int>(state_e), state);
+ PlatformResult result = MediaControllerPlaybackStateEnum.getName(state_e, state);
if (!result) {
- LoggerE("PlatformEnumToString failed, error: %s", result.message().c_str());
+ LoggerE("MediaControllerPlaybackStateEnum.getName() failed, error: %s", result.message().c_str());
return result;
}
return PlatformResult(ErrorCode::NO_ERROR);
}
-PlatformResult Types::ConvertPlaybackPosition(mc_playback_h playback_h, double* position) {
+PlatformResult ConvertPlaybackPosition(mc_playback_h playback_h, double* position) {
ScopeLogger();
int ret;
@@ -168,35 +140,30 @@ PlatformResult Types::ConvertPlaybackPosition(mc_playback_h playback_h, double*
return PlatformResult(ErrorCode::NO_ERROR);
}
-PlatformResult Types::ConvertMetadata(mc_metadata_h metadata_h, picojson::object* metadata) {
+PlatformResult ConvertMetadata(mc_metadata_h metadata_h, picojson::object* metadata) {
ScopeLogger();
- std::map<std::string, int> metadata_fields;
- PlatformResult result =
- GetPlatformEnumMap(Types::kMediaControllerMetadataAttribute, &metadata_fields);
- if (!result) {
- LoggerE("GetPlatformEnumMap failed, error: %s", result.message().c_str());
- return result;
- }
-
char* value = nullptr;
SCOPE_EXIT {
free(value);
};
- for (auto& field : metadata_fields) {
- int ret = mc_client_get_metadata(metadata_h, static_cast<mc_meta_e>(field.second), &value);
+ for (auto entry: MediaControllerMetadataAttributeEnum) {
+ int ret = mc_metadata_get(metadata_h, entry.second, &value);
if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error getting metadata",
- ("mc_client_get_metadata(%s) error: %d, message: %s",
- field.first.c_str(), ret, get_error_message(ret)));
+ ("mc_metadata_get(%s) error: %d, message: %s", entry.first.c_str(),
+ ret, get_error_message(ret)));
}
- (*metadata)[field.first] = picojson::value(std::string(value ? value : ""));
+ (*metadata)[entry.first] = picojson::value(std::string(value ? value : ""));
}
return PlatformResult(ErrorCode::NO_ERROR);
}
+} // types
+
+
} // namespace mediacontroller
} // namespace extension
diff --git a/src/mediacontroller/mediacontroller_types.h b/src/mediacontroller/mediacontroller_types.h
index 20966aaf..6b9eeab9 100644
--- a/src/mediacontroller/mediacontroller_types.h
+++ b/src/mediacontroller/mediacontroller_types.h
@@ -23,38 +23,32 @@
#include <string>
#include "common/platform_result.h"
+#include "common/platform_enum.h"
+
namespace extension {
namespace mediacontroller {
-typedef std::map<std::string, std::map<std::string, int>> PlatformEnumMap;
-typedef std::map<std::string, std::map<int, std::string>> PlatformEnumReverseMap;
typedef std::function<void(picojson::value*)> JsonCallback;
-class Types {
- public:
- static const std::string kMediaControllerServerState;
- static const std::string kMediaControllerPlaybackState;
- static const std::string kMediaControllerMetadataAttribute;
-
- static common::PlatformResult GetPlatformEnumMap(const std::string& type,
- std::map<std::string, int>* platform_str);
+namespace types {
- static common::PlatformResult StringToPlatformEnum(const std::string& type,
- const std::string& value, int* platform_enum);
+common::PlatformResult ConvertPlaybackState(mc_playback_h playback_h, std::string* state);
+common::PlatformResult ConvertContentAgeRating(mc_playback_h playback_h, std::string* state);
+common::PlatformResult ConvertPlaybackPosition(mc_playback_h playback_h, double* position);
+common::PlatformResult ConvertMetadata(mc_metadata_h metadata_h, picojson::object* metadata);
+common::PlatformResult ConvertContentType(mc_playback_h playback_h, std::string* contentType);
- static common::PlatformResult PlatformEnumToString(const std::string& type, int value,
- std::string* platform_str);
+extern const common::PlatformEnum<mc_server_state_e> MediaControllerServerStateEnum;
+extern const common::PlatformEnum<mc_playback_states_e> MediaControllerPlaybackStateEnum;
+extern const common::PlatformEnum<mc_playback_action_e> MediaControllerPlaybackActionEnum;
+extern const common::PlatformEnum<mc_meta_e> MediaControllerMetadataAttributeEnum;
+extern const common::PlatformEnum<mc_repeat_mode_e> MediaControllerRepeatModeEnum;
+extern const common::PlatformEnum<mc_content_age_rating_e> MediaControllerContentAgeRatingEnum;
+extern const common::PlatformEnum<mc_content_type_e> MediaControllerContentTypeEnum;
- static common::PlatformResult ConvertPlaybackState(mc_playback_h playback_h, std::string* state);
- static common::PlatformResult ConvertPlaybackPosition(mc_playback_h playback_h, double* position);
- static common::PlatformResult ConvertMetadata(mc_metadata_h metadata_h,
- picojson::object* metadata);
+} // namespace types
- private:
- static const PlatformEnumMap platform_enum_map_;
- static PlatformEnumReverseMap platform_enum_reverse_map_;
-};
} // namespace mediacontroller
} // namespace extension
diff --git a/src/messageport/messageport_api.js b/src/messageport/messageport_api.js
index 2cb4de75..00e77435 100755
--- a/src/messageport/messageport_api.js
+++ b/src/messageport/messageport_api.js
@@ -14,24 +14,22 @@
* limitations under the License.
*/
-var JSON_ = xwalk.JSON;
var validator_ = xwalk.utils.validator;
var types_ = validator_.Types;
var type_ = xwalk.utils.type;
var converter_ = xwalk.utils.converter;
-var privUtils_ = xwalk.utils;
+var native_ = new xwalk.utils.NativeManager(extension);
+
+var LOCAL_MESSAGE_PORT_LISTENER_ID = 'LocalMessagePortListener';
var callbackId = 0;
var callbacks = {};
var ports = [];
-extension.setMessageListener(function(json) {
- var msg = JSON_.parse(json);
- var listeners = callbacks[msg['local_port_id']];
+function MessagePortChangeCallback(msg) {
+ var listeners = callbacks[msg['localPortId']];
var rmp;
- privUtils_.log('Listeners length:' + listeners.length);
-
if (!msg.hasOwnProperty('remotePort')) rmp = null;
else rmp = new RemoteMessagePort(msg.remotePort, msg.remoteAppId, msg.trusted);
for (var i = 0; i < listeners.length; i++) {
@@ -40,69 +38,12 @@ extension.setMessageListener(function(json) {
func(msg.message, rmp);
}, 0);
}
-});
+}
function nextCallbackId() {
return callbackId++;
}
-var ExceptionMap = {
- UnknownError: WebAPIException.UNKNOWN_ERR,
- TypeMismatchError: WebAPIException.TYPE_MISMATCH_ERR,
- InvalidValuesError: WebAPIException.INVALID_VALUES_ERR,
- IOError: WebAPIException.IO_ERR,
- ServiceNotAvailableError: WebAPIException.SERVICE_NOT_AVAILABLE_ERR,
- SecurityError: WebAPIException.SECURITY_ERR,
- NetworkError: WebAPIException.NETWORK_ERR,
- NotSupportedError: WebAPIException.NOT_SUPPORTED_ERR,
- NotFoundError: WebAPIException.NOT_FOUND_ERR,
- InvalidAccessError: WebAPIException.INVALID_ACCESS_ERR,
- AbortError: WebAPIException.ABORT_ERR,
- QuotaExceededError: WebAPIException.QUOTA_EXCEEDED_ERR
-};
-
-function callNative(cmd, args) {
- var json = { cmd: cmd, args: args };
- var argjson = JSON_.stringify(json);
- var resultString = extension.internal.sendSyncMessage(argjson);
- var result = JSON_.parse(resultString);
-
- if (typeof result !== 'object') {
- throw new WebAPIException(WebAPIException.UNKNOWN_ERR);
- }
-
- if (result['status'] == 'success') {
- if (result['result']) {
- return result['result'];
- }
- return true;
- } else if (result['status'] == 'error') {
- var err = result['error'];
- if (err) {
- if (ExceptionMap[err.name]) {
- throw new WebAPIException(ExceptionMap[err.name], err.message);
- } else {
- throw new WebAPIException(WebAPIException.UNKNOWN_ERR, err.message);
- }
- }
- return false;
- }
-}
-
-function callNativeWithCallback(cmd, args, callback) {
- if (callback) {
- var id = nextCallbackId();
- args['callbackId'] = id;
- callbacks[id] = callback;
- }
-
- return callNative(cmd, args);
-}
-
-function SetReadOnlyProperty(obj, n, v) {
- Object.defineProperty(obj, n, { value: v, writable: false });
-}
-
function MessagePortManager() {
// constructor of MessagePortManager
}
@@ -119,22 +60,22 @@ MessagePortManager.prototype.requestLocalMessagePort = function(localMessagePort
);
}
- var localPortId;
+ var localPortId; // TODO remove
var nativeParam = {
localMessagePortName: args.localMessagePortName
};
- try {
- localPortId = callNative(
- 'MessagePortManager_requestLocalMessagePort',
- nativeParam
- );
- } catch (e) {
- throw e;
- }
+ var result = native_.callSync(
+ 'MessagePortManager_requestLocalMessagePort',
+ nativeParam
+ );
- var returnObject = new LocalMessagePort(args.localMessagePortName, false);
- ports[nativeParam.localMessagePortName] = localPortId;
+ if (native_.isSuccess(result)) {
+ var returnObject = new LocalMessagePort(args.localMessagePortName, false);
+ ports[nativeParam.localMessagePortName] = native_.getResultObject(result);
+ } else {
+ throw native_.getErrorObject(result);
+ }
return returnObject;
};
@@ -157,17 +98,17 @@ MessagePortManager.prototype.requestTrustedLocalMessagePort = function(
localMessagePortName: args.localMessagePortName
};
- try {
- var localPortId = callNative(
- 'MessagePortManager_requestTrustedLocalMessagePort',
- nativeParam
- );
- } catch (e) {
- throw e;
- }
+ var result = native_.callSync(
+ 'MessagePortManager_requestTrustedLocalMessagePort',
+ nativeParam
+ );
- var returnObject = new LocalMessagePort(args.localMessagePortName, true);
- ports[nativeParam.localMessagePortName] = localPortId;
+ if (native_.isSuccess(result)) {
+ var returnObject = new LocalMessagePort(args.localMessagePortName, true);
+ ports[nativeParam.localMessagePortName] = native_.getResultObject(result);
+ } else {
+ throw native_.getErrorObject(result);
+ }
return returnObject;
};
@@ -186,13 +127,13 @@ MessagePortManager.prototype.requestRemoteMessagePort = function(
remoteMessagePortName: args.remoteMessagePortName
};
- try {
- var syncResult = callNative(
- 'MessagePortManager_requestRemoteMessagePort',
- nativeParam
- );
- } catch (e) {
- throw e;
+ var result = native_.callSync(
+ 'MessagePortManager_requestRemoteMessagePort',
+ nativeParam
+ );
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
}
var returnObject = new RemoteMessagePort(
@@ -218,13 +159,13 @@ MessagePortManager.prototype.requestTrustedRemoteMessagePort = function(
remoteMessagePortName: args.remoteMessagePortName
};
- try {
- var syncResult = callNative(
- 'MessagePortManager_requestTrustedRemoteMessagePort',
- nativeParam
- );
- } catch (e) {
- throw e;
+ var result = native_.callSync(
+ 'MessagePortManager_requestTrustedRemoteMessagePort',
+ nativeParam
+ );
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
}
var returnObject = new RemoteMessagePort(
@@ -248,6 +189,8 @@ LocalMessagePort.prototype.addMessagePortListener = function(listener) {
{ name: 'listener', type: types_.FUNCTION, nullable: false }
]);
+ native_.addListener(LOCAL_MESSAGE_PORT_LISTENER_ID, MessagePortChangeCallback);
+
var portId = ports[this.messagePortName];
if (!callbacks.hasOwnProperty(portId)) callbacks[portId] = [];
@@ -312,10 +255,10 @@ RemoteMessagePort.prototype.sendMessage = function() {
}
]);
- var filtered_data = new Array(args.data.length);
- var unique_data_key = {};
- var data_length = args.data.length;
- for (var i = 0; i < data_length; i++) {
+ var filteredData = new Array(args.data.length);
+ var uniqueDataKey = {};
+ var dataLength = args.data.length;
+ for (var i = 0; i < dataLength; i++) {
if (!args.data[i].hasOwnProperty('key')) {
throw new WebAPIException(
WebAPIException.INVALID_VALUES_ERR,
@@ -329,7 +272,7 @@ RemoteMessagePort.prototype.sendMessage = function() {
'Property \'key\' should not be empty.'
);
}
- if (true === unique_data_key[key]) {
+ if (true === uniqueDataKey[key]) {
throw new WebAPIException(
WebAPIException.INVALID_VALUES_ERR,
'Property \'key\' should not be duplicated.'
@@ -337,7 +280,7 @@ RemoteMessagePort.prototype.sendMessage = function() {
}
var value = args.data[i].value;
if (type_.isString(value)) {
- filtered_data[i] = { key: key, value: value, valueType: 'stringValueType' };
+ filteredData[i] = { key: key, value: value, valueType: 'stringValueType' };
} else if (type_.isArray(value)) {
var arrayMember = value[0];
if (type_.isString(arrayMember)) {
@@ -349,7 +292,7 @@ RemoteMessagePort.prototype.sendMessage = function() {
);
}
}
- filtered_data[i] = {
+ filteredData[i] = {
key: key,
value: value,
valueType: 'stringArrayValueType'
@@ -361,7 +304,7 @@ RemoteMessagePort.prototype.sendMessage = function() {
'Data is not octet array'
);
}
- filtered_data[i] = {
+ filteredData[i] = {
key: key,
value: value,
valueType: 'byteStreamValueType'
@@ -375,7 +318,7 @@ RemoteMessagePort.prototype.sendMessage = function() {
);
}
}
- filtered_data[i] = {
+ filteredData[i] = {
key: key,
value: value,
valueType: 'byteStreamArrayValueType'
@@ -383,26 +326,30 @@ RemoteMessagePort.prototype.sendMessage = function() {
}
} else {
// convert any other value to string -> backward compatibility
- filtered_data[i] = {
+ filteredData[i] = {
key: key,
value: converter_.toString(value),
valueType: 'stringValueType'
};
}
- unique_data_key[key] = true;
+ uniqueDataKey[key] = true;
}
var nativeParam = {
appId: this.appId,
messagePortName: this.messagePortName,
- data: filtered_data,
+ data: filteredData,
trusted: this.isTrusted,
- local_port_id: args.localMessagePort
+ localPortId: args.localMessagePort
? ports[args.localMessagePort.messagePortName]
: -1
};
- var syncResult = callNative('RemoteMessagePort_sendMessage', nativeParam);
+ var result = native_.callSync('RemoteMessagePort_sendMessage', nativeParam);
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
};
exports = new MessagePortManager();
diff --git a/src/messageport/messageport_instance.cc b/src/messageport/messageport_instance.cc
index 28df4999..4b342d46 100644
--- a/src/messageport/messageport_instance.cc
+++ b/src/messageport/messageport_instance.cc
@@ -163,7 +163,8 @@ static void OnReceiveLocalMessage(int local_port_id, const char* remote_app_id,
picojson::value::object o;
picojson::value::array data;
- o["local_port_id"] = picojson::value(static_cast<double>(local_port_id));
+ o["listenerId"] = picojson::value("LocalMessagePortListener");
+ o["localPortId"] = picojson::value(static_cast<double>(local_port_id));
if (remote_port) {
o["remoteAppId"] = picojson::value(remote_app_id);
@@ -282,29 +283,17 @@ void MessageportInstance::MessagePortManagerRequestremotemessageport(const picoj
portCheck ? "true" : "false");
LoggerD("Error code: %d (%s)", ret, get_error_message(ret));
- if (ret == MESSAGE_PORT_ERROR_NONE) {
+ if (MESSAGE_PORT_ERROR_NONE == ret) {
if (portCheck) {
ReportSuccess(out);
} else {
LogAndReportError(NotFoundException("The port of the target application is not found"), out);
}
- } else if (ret == MESSAGE_PORT_ERROR_INVALID_PARAMETER) {
- LogAndReportError(
- InvalidValuesException("An input parameter contains an invalid value."), out,
- ("message_port_check_remote_port error: %d (%s)", ret, get_error_message(ret)));
- } else if (ret == MESSAGE_PORT_ERROR_OUT_OF_MEMORY) {
- LogAndReportError(
- UnknownException("Out of memory."), out,
- ("message_port_check_remote_port error: %d (%s)", ret, get_error_message(ret)));
- } else if (ret == MESSAGE_PORT_ERROR_IO_ERROR) {
+ } else if (MESSAGE_PORT_ERROR_IO_ERROR == ret) {
// IO error means that remote port does not exist
LogAndReportError(
NotFoundException("The port of the target application is not found"), out,
("message_port_check_remote_port error: %d (%s)", ret, get_error_message(ret)));
- } else if (ret == MESSAGE_PORT_ERROR_PORT_NOT_FOUND) {
- LogAndReportError(
- NotFoundException("The port of the target application is not found"), out,
- ("message_port_check_remote_port error: %d (%s)", ret, get_error_message(ret)));
} else {
LogAndReportError(
UnknownException("Unknown Error"), out,
@@ -330,30 +319,18 @@ void MessageportInstance::MessagePortManagerRequesttrustedremotemessageport(
portCheck ? "true" : "false");
LoggerD("Error code: %d (%s)", ret, get_error_message(ret));
- if (ret == MESSAGE_PORT_ERROR_NONE) {
+ if (MESSAGE_PORT_ERROR_NONE == ret) {
if (portCheck) {
ReportSuccess(out);
} else {
LogAndReportError(NotFoundException("The port of the target application is not found"), out);
}
- } else if (ret == MESSAGE_PORT_ERROR_INVALID_PARAMETER) {
- LogAndReportError(
- InvalidValuesException("An input parameter contains an invalid value."), out,
- ("message_port_check_trusted_remote_port error: %d (%s)", ret, get_error_message(ret)));
- } else if (ret == MESSAGE_PORT_ERROR_OUT_OF_MEMORY) {
- LogAndReportError(
- UnknownException("Out of memory."), out,
- ("message_port_check_trusted_remote_port error: %d (%s)", ret, get_error_message(ret)));
- } else if (ret == MESSAGE_PORT_ERROR_IO_ERROR) {
+ } else if (MESSAGE_PORT_ERROR_IO_ERROR == ret) {
// IO error means that remote port does not exist
LogAndReportError(
NotFoundException("The port of the target application is not found"), out,
("message_port_check_trusted_remote_port error: %d (%s)", ret, get_error_message(ret)));
- } else if (ret == MESSAGE_PORT_ERROR_PORT_NOT_FOUND) {
- LogAndReportError(
- NotFoundException("The port of the target application is not found"), out,
- ("message_port_check_trusted_remote_port error: %d (%s)", ret, get_error_message(ret)));
- } else if (ret == MESSAGE_PORT_ERROR_CERTIFICATE_NOT_MATCH) {
+ } else if (MESSAGE_PORT_ERROR_CERTIFICATE_NOT_MATCH == ret) {
LogAndReportError(
UnknownException("The remote application is not signed with the same certificate"), out,
("message_port_check_trusted_remote_port error: %d (%s)", ret, get_error_message(ret)));
@@ -371,7 +348,7 @@ void MessageportInstance::RemoteMessagePortSendmessage(const picojson::value& ar
const std::string& message_port_name = args.get("messagePortName").get<std::string>();
std::vector<picojson::value> data = args.get("data").get<picojson::array>();
- long local_port_id = static_cast<long>(args.get("local_port_id").get<double>());
+ long local_port_id = static_cast<long>(args.get("localPortId").get<double>());
bool trusted = args.get("trusted").get<bool>();
int result;
diff --git a/src/messaging/DBus/MessageProxy.h b/src/messaging/DBus/MessageProxy.h
index 4089fcdd..aeeb96b8 100644
--- a/src/messaging/DBus/MessageProxy.h
+++ b/src/messaging/DBus/MessageProxy.h
@@ -18,7 +18,6 @@
#ifndef __TIZEN_MESSAGE_PROXY_H
#define __TIZEN_MESSAGE_PROXY_H
-#include <dbus/dbus-glib.h>
#include <dbus/dbus.h>
#include <email-types.h>
#include <gio/gio.h>
diff --git a/src/messaging/MsgCommon/AttributeRangeFilter.h b/src/messaging/MsgCommon/AttributeRangeFilter.h
index 6d93cbfe..267faa2a 100644
--- a/src/messaging/MsgCommon/AttributeRangeFilter.h
+++ b/src/messaging/MsgCommon/AttributeRangeFilter.h
@@ -54,7 +54,6 @@ class AttributeRangeFilter : public AbstractFilter {
*/
AttributeRangeFilterPtr castToAttributeRangeFilter(AbstractFilterPtr from);
-
} // Tizen
} // DeviceAPI
diff --git a/src/messaging/conversations_change_callback.cc b/src/messaging/conversations_change_callback.cc
index fe5f7e0f..a53c8d3f 100644
--- a/src/messaging/conversations_change_callback.cc
+++ b/src/messaging/conversations_change_callback.cc
@@ -74,7 +74,7 @@ ConversationPtrVector ConversationsChangeCallback::filterConversations(
LoggerD("[%d] matched filter: %s", i, matched ? "YES" : "NO");
}
- LoggerD("returning matching %d of %d conversations", filtered_conversations.size(),
+ LoggerD("returning matching %zu of %zu conversations", filtered_conversations.size(),
source_conversations.size());
return filtered_conversations;
@@ -85,7 +85,7 @@ ConversationPtrVector ConversationsChangeCallback::filterConversations(
}
void ConversationsChangeCallback::added(const ConversationPtrVector& conversations) {
- ScopeLogger("conversations.size() = %d", conversations.size());
+ ScopeLogger("conversations.size() = %zu", conversations.size());
if (!m_is_act) {
return;
}
@@ -104,14 +104,14 @@ void ConversationsChangeCallback::added(const ConversationPtrVector& conversatio
};
for_each(filtered.begin(), filtered.end(), each);
- LoggerD("Calling:%s with:%d added conversations", CONVERSATIONSADDED, filtered.size());
+ LoggerD("Calling:%s with:%zu added conversations", CONVERSATIONSADDED, filtered.size());
m_callback_data.SetAction(CONVERSATIONSADDED, picojson::value(array));
m_callback_data.AddAndPost(PostPriority::MEDIUM);
}
void ConversationsChangeCallback::updated(const ConversationPtrVector& conversations) {
- ScopeLogger("conversations.size() = %d", conversations.size());
+ ScopeLogger("conversations.size() = %zu", conversations.size());
if (!m_is_act) {
return;
}
@@ -130,14 +130,14 @@ void ConversationsChangeCallback::updated(const ConversationPtrVector& conversat
};
for_each(filtered.begin(), filtered.end(), each);
- LoggerD("Calling:%s with:%d added conversations", CONVERSATIONSUPDATED, filtered.size());
+ LoggerD("Calling:%s with:%zu added conversations", CONVERSATIONSUPDATED, filtered.size());
m_callback_data.SetAction(CONVERSATIONSUPDATED, picojson::value(array));
m_callback_data.AddAndPost(PostPriority::LOW);
}
void ConversationsChangeCallback::removed(const ConversationPtrVector& conversations) {
- ScopeLogger("conversations.size() = %d", conversations.size());
+ ScopeLogger("conversations.size() = %zu", conversations.size());
if (!m_is_act) {
return;
}
@@ -156,7 +156,7 @@ void ConversationsChangeCallback::removed(const ConversationPtrVector& conversat
};
for_each(filtered.begin(), filtered.end(), each);
- LoggerD("Calling:%s with:%d added conversations", CONVERSATIONSREMOVED, filtered.size());
+ LoggerD("Calling:%s with:%zu added conversations", CONVERSATIONSREMOVED, filtered.size());
m_callback_data.SetAction(CONVERSATIONSREMOVED, picojson::value(array));
m_callback_data.AddAndPost(PostPriority::LAST);
diff --git a/src/messaging/email_manager.cc b/src/messaging/email_manager.cc
index aeec4e26..5b89dd68 100644
--- a/src/messaging/email_manager.cc
+++ b/src/messaging/email_manager.cc
@@ -17,8 +17,11 @@
//#include <JSWebAPIErrorFactory.h>
//#include <JSWebAPIError.h>
//#include <JSUtil.h>
+#include <chrono>
+#include <list>
#include <memory>
#include <sstream>
+#include <thread>
#include "common/logger.h"
#include "common/platform_exception.h"
#include "common/scope_exit.h"
@@ -62,6 +65,7 @@
using namespace common;
using namespace extension::tizen;
+using namespace std::chrono_literals;
namespace extension {
namespace messaging {
@@ -69,6 +73,16 @@ namespace messaging {
namespace {
const int ACCOUNT_ID_NOT_INITIALIZED = -1;
const std::string FIND_FOLDERS_ATTRIBUTE_ACCOUNTID_NAME = "serviceId";
+
+bool isFirstInThread(const Message* message) {
+ ScopeLogger();
+ return message->getId() == message->getConversationId();
+}
+
+bool isFirstInThread(const email_mail_data_t* mail_data) {
+ ScopeLogger();
+ return mail_data->mail_id == mail_data->thread_id;
+}
} // anonymous namespace
EmailManager::EmailManager() : m_slot_size(-1), m_is_initialized(false) {
@@ -251,11 +265,68 @@ PlatformResult EmailManager::addMessagePlatform(int account_id, std::shared_ptr<
}
}
- err = email_get_mail_data(message->getId(), &mail_data_final);
- if (EMAIL_ERROR_NONE != err) {
- return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Couldn't retrieve added mail data",
- ("email_get_mail_data error: %d (%s)", err, get_error_message(err)));
+ /*
+ * If the message is first in its thread (its mail_id == thread_id)
+ * and it has an attachment, there is some delay between addEmailAttachments
+ * return and the corresponding update of message's record in the internal
+ * email DB.
+ *
+ * The internal DB is queried for mail_data_final below, but due to
+ * the mentioned delay, it may return mail_data_final, that is not
+ * up-to-date, i.e with mail_id != thread_id).
+ * If such situation occurs, up to MAX_RETRIES retries of calling
+ * email_get_mail_data are performed.
+ * If returned mail_data_final is up-to-date before reaching retries limit,
+ * the returned value is used to set mail properties.
+ * If returned mail_data_final is still not up-to-date, thread_id of the message
+ * is set manually to mail_id.
+ */
+
+ if (isFirstInThread(mail_data)) {
+ int retry = 0;
+ const int MAX_RETRIES = 5;
+ for (; retry < MAX_RETRIES; ++retry) {
+ err = email_get_mail_data(message->getId(), &mail_data_final);
+
+ if (EMAIL_ERROR_NONE != err) {
+ /*
+ * TODO: in the case of email_get_mail_data failure,
+ * the message should be removed from the databse
+ */
+ return LogAndCreateResult(
+ ErrorCode::UNKNOWN_ERR, "Couldn't add message to draft mailbox",
+ ("email_get_mail_data error: %d (%s)", err, get_error_message(err)));
+ }
+
+ if (isFirstInThread(mail_data) && isFirstInThread(mail_data_final)) {
+ LoggerD("Message adding process finished after %d retries. mail_id == thread_id", retry);
+ break;
+ }
+
+ int free_error = email_free_mail_data(&mail_data_final, 1);
+ if (EMAIL_ERROR_NONE != free_error) {
+ LoggerW("email_free_mail_data error: %d, %s", free_error, get_error_message(free_error));
+ }
+ LoggerD("Retry number %d failed", retry);
+ std::this_thread::sleep_for(100ms);
+ }
+
+ if (MAX_RETRIES == retry) {
+ LoggerD(
+ "Message adding process not finished after %d retries. Setting proper conversationId "
+ "manually",
+ retry);
+ mail_data_final->thread_id = mail_data_final->mail_id;
+ }
+ } else {
+ err = email_get_mail_data(message->getId(), &mail_data_final);
+ if (EMAIL_ERROR_NONE != err) {
+ return LogAndCreateResult(
+ ErrorCode::UNKNOWN_ERR, "Couldn't add message to draft mailbox",
+ ("email_get_mail_data error: %d (%s)", err, get_error_message(err)));
+ }
}
+
ret = message->updateEmailMessage(*mail_data_final);
if (ret.IsError()) {
return ret;
@@ -575,7 +646,7 @@ PlatformResult EmailManager::loadMessageAttachment(MessageAttachmentCallbackData
return platform_result;
}
- LoggerD("Mail: [%d] contains: [%d] attachments", msgAttachment->getMessageId(),
+ LoggerD("Mail: [%d] contains: [%zu] attachments", msgAttachment->getMessageId(),
attachments.size());
auto it = attachments.begin();
@@ -821,7 +892,7 @@ void EmailManager::removeStatusCallback(const std::vector<int>& ids,
if (it != m_deleteRequests.end()) {
LoggerD("Found request");
if (NOTI_MAIL_DELETE_FINISH == status) {
- LoggerD("Successfully removed %d mails", ids.size());
+ LoggerD("Successfully removed %zu mails", ids.size());
it->messagesDeleted += ids.size();
}
MessagesCallbackUserData* callback = it->callback;
@@ -915,6 +986,7 @@ PlatformResult EmailManager::UpdateMessagesPlatform(MessagesCallbackUserData* ca
std::lock_guard<std::mutex> lock(m_mutex);
std::vector<std::shared_ptr<Message>> messages = callback->getMessages();
+ std::list<std::shared_ptr<Message>> firstInThreadAndHasAttachment;
MessageType type = callback->getMessageServiceType();
for (auto it = messages.begin(); it != messages.end(); ++it) {
if ((*it)->getType() != type) {
@@ -927,7 +999,11 @@ PlatformResult EmailManager::UpdateMessagesPlatform(MessagesCallbackUserData* ca
if (ret.IsError()) return ret;
if ((*it)->getHasAttachment()) {
- LoggerD("Message has attachments. Workaround need to be used.");
+ if (isFirstInThread(it->get())) {
+ // Messages with attachments, that are first in their threads are added
+ // to the container, to be processed later in this function
+ firstInThreadAndHasAttachment.push_back(*it);
+ }
// Update of mail on server using function email_update_mail() is not possible.
// Attachment is updated only locally (can't be later loaded from server),
// so use of workaround is needed:
@@ -944,8 +1020,8 @@ PlatformResult EmailManager::UpdateMessagesPlatform(MessagesCallbackUserData* ca
// storing old message id
(*it)->setOldId(mail->mail_id);
// deleting old mail
- LoggerD("mail deleted = [%d]\n", mail->mail_id);
error = email_delete_mail(mail->mailbox_id, &mail->mail_id, 1, 1);
+ LoggerD("mail deleted = [%d]\n", mail->mail_id);
if (EMAIL_ERROR_NONE != error) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Error while deleting old mail on update",
@@ -961,6 +1037,73 @@ PlatformResult EmailManager::UpdateMessagesPlatform(MessagesCallbackUserData* ca
}
}
}
+
+ if (firstInThreadAndHasAttachment.size() == 0) {
+ return PlatformResult(ErrorCode::NO_ERROR);
+ }
+
+ /*
+ * If a message with attachment, that is first in its thread was updated,
+ * the update process consists of adding a new message - updated version
+ * of the original and removing the original.
+ *
+ * After the original mail is deleted, the thread_id of the updated version
+ * changes - it is now identical to the mail_id of the new message.
+ * The change should be reflected in the updated message, sent to the JS
+ * layer. The code below sets proper thread_id for such messages and unsets
+ * inResponseTo fields.
+ *
+ * A few retries with sleeps between them are performed, to ensure, that after
+ * this function returns, messages returned to the JS layer and
+ * corresponding records in the mail DB have the same thread_ids. Due to a
+ * delay between calling email_delete_mail function and the update of records
+ * in the database, some time is needed.
+ */
+ email_mail_data_t* mail_data{nullptr};
+ int retry = 0;
+ const int MAX_RETRIES = 5;
+ for (; retry < MAX_RETRIES; ++retry) {
+ std::this_thread::sleep_for(100ms);
+ auto it = firstInThreadAndHasAttachment.begin();
+ while (it != firstInThreadAndHasAttachment.end()) {
+ error = email_get_mail_data((*it)->getId(), &mail_data);
+ if (EMAIL_ERROR_NONE != error) {
+ return LogAndCreateResult(
+ ErrorCode::UNKNOWN_ERR, "Couldn't add message to draft mailbox",
+ ("email_get_mail_data error: %d (%s)", error, get_error_message(error)));
+ }
+
+ if (isFirstInThread(mail_data)) {
+ (*it)->setConversationId(mail_data->thread_id);
+ (*it)->unsetInResponseTo();
+ it = firstInThreadAndHasAttachment.erase(it);
+ } else {
+ ++it;
+ }
+
+ int free_error = email_free_mail_data(&mail_data, 1);
+ if (EMAIL_ERROR_NONE != free_error) {
+ LoggerW("email_free_mail_data error: %d, %s", free_error, get_error_message(free_error));
+ }
+ }
+
+ if (firstInThreadAndHasAttachment.size() == 0) {
+ LoggerD("Message updating process finished after %d retries", retry);
+ break;
+ }
+
+ LoggerD("Message update retry number %d finished", retry);
+ }
+
+ if (MAX_RETRIES == retry) {
+ LoggerW("Message updating process not finished after %d retries.", retry);
+ for (auto& message : firstInThreadAndHasAttachment) {
+ LoggerD("Setting proper conversationId manually, message id: %d", message->getId());
+ message->setConversationId(message->getId());
+ message->unsetInResponseTo();
+ }
+ }
+
return PlatformResult(ErrorCode::NO_ERROR);
}
@@ -1047,7 +1190,7 @@ void EmailManager::findMessages(FindMsgCallbackUserData* callback) {
}
// Complete task
- LoggerD("callback: %p error: %d messages.size() = %d", callback, callback->IsError(),
+ LoggerD("callback: %p error: %d messages.size() = %zu", callback, callback->IsError(),
callback->getMessages().size());
if (callback->IsError()) {
@@ -1103,7 +1246,7 @@ void EmailManager::findConversations(ConversationCallbackData* callback) {
}
// Complete task
- LoggerD("callback: %p error:%d conversations.size()=%d", callback, callback->IsError(),
+ LoggerD("callback: %p error:%d conversations.size()=%zu", callback, callback->IsError(),
callback->getConversations().size());
if (callback->IsError()) {
@@ -1222,7 +1365,7 @@ void EmailManager::findFolders(FoldersCallbackData* callback) {
}
// Complete task
- LoggerD("callback: %p error:%d folders.size()=%d", callback, callback->IsError(),
+ LoggerD("callback: %p error:%d folders.size()=%zu", callback, callback->IsError(),
callback->getFolders().size());
if (callback->IsError()) {
diff --git a/src/messaging/folders_change_callback.cc b/src/messaging/folders_change_callback.cc
index 6ceda0b2..8bb67f25 100644
--- a/src/messaging/folders_change_callback.cc
+++ b/src/messaging/folders_change_callback.cc
@@ -69,7 +69,7 @@ FolderPtrVector FoldersChangeCallback::filterFolders(tizen::AbstractFilterPtr fi
}
void FoldersChangeCallback::added(const FolderPtrVector& folders) {
- ScopeLogger("folders.size() = %d", folders.size());
+ ScopeLogger("folders.size() = %zu", folders.size());
if (!m_is_act) {
return;
}
@@ -88,14 +88,14 @@ void FoldersChangeCallback::added(const FolderPtrVector& folders) {
};
for_each(filtered.begin(), filtered.end(), each);
- LoggerD("Calling:%s with:%d added folders", FOLDERSADDED, filtered.size());
+ LoggerD("Calling:%s with:%zu added folders", FOLDERSADDED, filtered.size());
m_callback_data.SetAction(FOLDERSADDED, picojson::value(array));
m_callback_data.AddAndPost(PostPriority::MEDIUM);
}
void FoldersChangeCallback::updated(const FolderPtrVector& folders) {
- ScopeLogger("folders.size() = %d", folders.size());
+ ScopeLogger("folders.size() = %zu", folders.size());
if (!m_is_act) {
return;
}
@@ -114,14 +114,14 @@ void FoldersChangeCallback::updated(const FolderPtrVector& folders) {
};
for_each(filtered.begin(), filtered.end(), each);
- LoggerD("Calling:%s with:%d updated folders", FOLDERSUPDATED, filtered.size());
+ LoggerD("Calling:%s with:%zu updated folders", FOLDERSUPDATED, filtered.size());
m_callback_data.SetAction(FOLDERSUPDATED, picojson::value(array));
m_callback_data.AddAndPost(PostPriority::LOW);
}
void FoldersChangeCallback::removed(const FolderPtrVector& folders) {
- ScopeLogger("folders.size() = %d", folders.size());
+ ScopeLogger("folders.size() = %zu", folders.size());
if (!m_is_act) {
return;
}
@@ -140,7 +140,7 @@ void FoldersChangeCallback::removed(const FolderPtrVector& folders) {
};
for_each(filtered.begin(), filtered.end(), each);
- LoggerD("Calling:%s with:%d removed folders", FOLDERSREMOVED, filtered.size());
+ LoggerD("Calling:%s with:%zu removed folders", FOLDERSREMOVED, filtered.size());
m_callback_data.SetAction(FOLDERSREMOVED, picojson::value(array));
m_callback_data.AddAndPost(PostPriority::LAST);
diff --git a/src/messaging/message.cc b/src/messaging/message.cc
index 80825fa4..89d0a05b 100644
--- a/src/messaging/message.cc
+++ b/src/messaging/message.cc
@@ -279,6 +279,11 @@ void Message::setInResponseTo(int inresp) {
m_in_response_set = true;
}
+void Message::unsetInResponseTo() {
+ m_in_response = -1;
+ m_in_response_set = false;
+}
+
void Message::setMessageStatus(MessageStatus status) {
m_status = status;
}
@@ -591,8 +596,8 @@ PlatformResult Message::addEmailAttachments(std::shared_ptr<Message> message) {
AttachmentPtrVector attachments = message->getMessageAttachments();
AttachmentPtrVector inlineAttachments = message->getBody()->getInlineAttachments();
- LoggerD("Attachments size: %d", attachments.size());
- LoggerD("Inline attachments size: %d", inlineAttachments.size());
+ LoggerD("Attachments size: %zu", attachments.size());
+ LoggerD("Inline attachments size: %zu", inlineAttachments.size());
LoggerD("Adding attachments for mail id = [%d]\n", message->getId());
for (auto it = attachments.begin(); it != attachments.end(); ++it) {
PlatformResult ret = addSingleEmailAttachment(message, *it, AttachmentType::EXTERNAL);
@@ -669,7 +674,7 @@ PlatformResult Message::addSMSRecipientsToStruct(const std::vector<std::string>&
for (unsigned int i = 0; i < size; ++i) {
char* address = const_cast<char*>(recipients.at(i).c_str());
- LoggerD("[%d] address:[%s]", i, address);
+ LoggerD("[%u] address:[%s]", i, address);
msg_struct_t tmpAddr = NULL;
if (MSG_SUCCESS == msg_list_add_item(msg, MSG_MESSAGE_ADDR_LIST_HND, &tmpAddr)) {
msg_set_int_value(tmpAddr, MSG_ADDRESS_INFO_ADDRESS_TYPE_INT, MSG_ADDRESS_TYPE_PLMN);
@@ -677,7 +682,7 @@ PlatformResult Message::addSMSRecipientsToStruct(const std::vector<std::string>&
msg_set_str_value(tmpAddr, MSG_ADDRESS_INFO_ADDRESS_VALUE_STR, address, strlen(address));
} else {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "failed to add address",
- ("failed to add address[%d] %s", i, address));
+ ("failed to add address[%u] %s", i, address));
}
}
return PlatformResult(ErrorCode::NO_ERROR);
@@ -696,7 +701,7 @@ PlatformResult Message::addMMSRecipientsToStruct(const std::vector<std::string>&
}
char* address = const_cast<char*>(recipients.at(i).c_str());
- LoggerD("[%d] address:[%s] address_type:%d type:%d", i, address, address_type, type);
+ LoggerD("[%u] address:[%s] address_type:%d type:%d", i, address, address_type, type);
int error = msg_list_add_item(msg, MSG_MESSAGE_ADDR_LIST_HND, &tmpAddr);
if (MSG_SUCCESS == error) {
@@ -705,7 +710,7 @@ PlatformResult Message::addMMSRecipientsToStruct(const std::vector<std::string>&
msg_set_str_value(tmpAddr, MSG_ADDRESS_INFO_ADDRESS_VALUE_STR, address, strlen(address));
} else {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "failed to add address",
- ("[%d] failed to add address: [%s], error: %d", i, address, error));
+ ("[%u] failed to add address: [%s], error: %d", i, address, error));
}
}
return PlatformResult(ErrorCode::NO_ERROR);
@@ -714,7 +719,7 @@ PlatformResult Message::addMMSRecipientsToStruct(const std::vector<std::string>&
PlatformResult Message::addMMSBodyAndAttachmentsToStruct(const AttachmentPtrVector& attach,
msg_struct_t& mms_struct,
Message* message) {
- ScopeLogger("attachments.size() = %zd", attach.size());
+ ScopeLogger("attachments.size() = %zu", attach.size());
int size = attach.size();
for (int i = 0; i < size; i++) {
@@ -805,7 +810,7 @@ PlatformResult Message::convertPlatformShortMessageToStruct(Message* message, ms
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "msg_get_message() Fail",
("msg_get_message() Fail [%d] (%s)", err, get_error_message(err)));
}
- LoggerD("Using existing msg for id: %d", id);
+ LoggerD("Using existing msg for id: %u", id);
} else { // id is not set - the message does not exist in database
MessageType msgType = message->getType();
if (msgType == MessageType::SMS) {
@@ -950,7 +955,7 @@ PlatformResult Message::convertPlatformShortMessageToStruct(Message* message, ms
}
// Set MMS attachments
AttachmentPtrVector attach_list = message->getMessageAttachments();
- LoggerD("Message(%p): id:%d subject:[%s] plainBody:[%s] contains %d attachments", message,
+ LoggerD("Message(%p): id:%d subject:[%s] plainBody:[%s] contains %zu attachments", message,
message->getId(), message->getSubject().c_str(),
message->getBody()->getPlainBody().c_str(), attach_list.size());
@@ -1209,7 +1214,8 @@ PlatformResult Message::setMMSBodyAndAttachmentsFromStruct(Message* message, msg
LoggerD(
"[p:%d, m:%d] added attachment: %p "
"(mime:0x%x mime:%s messageId:%d)",
- p, m, att, msg_media_type, msg_media_type_str.c_str(), ma->getMessageId());
+ p, m, att, (unsigned)msg_media_type, msg_media_type_str.c_str(),
+ ma->getMessageId());
}
msg_release_struct(&media);
@@ -1233,7 +1239,7 @@ PlatformResult Message::setMMSBodyAndAttachmentsFromStruct(Message* message, msg
LoggerW("Warning: body has not been set!");
}
- LoggerD("after MSG_MMS_PAGE_LIST attachments count is:%d", message->m_attachments.size());
+ LoggerD("after MSG_MMS_PAGE_LIST attachments count is:%zu", message->m_attachments.size());
// if there are some other attachments add it to attachments vector
msg_list_handle_t attach_list = NULL;
@@ -1269,8 +1275,8 @@ PlatformResult Message::setMMSBodyAndAttachmentsFromStruct(Message* message, msg
ma->setMimeType(type);
MessageAttachment* att = ma.get();
- LoggerD("[att:%d] added attachement: %p (mime:0x%x mime:%s path:%s id:%d)", i, att, tempInt,
- type.c_str(), infoStr, ma->getId());
+ LoggerD("[att:%d] added attachement: %p (mime:0x%x mime:%s path:%s id:%d)", i, att,
+ (unsigned)tempInt, type.c_str(), infoStr, ma->getId());
message->m_attachments.push_back(ma);
message->m_has_attachment = true;
@@ -1284,7 +1290,7 @@ PlatformResult Message::setMMSBodyAndAttachmentsFromStruct(Message* message, msg
("msg_get_list_handle error: %d (%s)", error, get_error_message(error)));
}
- LoggerD("after MSG_MMS_ATTACH_LIST attachments count is:%d", message->m_attachments.size());
+ LoggerD("after MSG_MMS_ATTACH_LIST attachments count is:%zu", message->m_attachments.size());
msg_release_struct(&mms_struct);
return PlatformResult(ErrorCode::NO_ERROR);
}
diff --git a/src/messaging/message.h b/src/messaging/message.h
index c4c5c15f..7562fc37 100644
--- a/src/messaging/message.h
+++ b/src/messaging/message.h
@@ -98,6 +98,7 @@ class Message : public FilterableObject {
virtual void setIsHighPriority(bool highpriority);
virtual void setSubject(std::string subject);
virtual void setInResponseTo(int inresp);
+ virtual void unsetInResponseTo();
virtual void setMessageStatus(MessageStatus status);
virtual void setMessageAttachments(AttachmentPtrVector& attachments);
virtual void setServiceId(int service_id);
diff --git a/src/messaging/messages_change_callback.cc b/src/messaging/messages_change_callback.cc
index e0567dcd..e0a48bec 100644
--- a/src/messaging/messages_change_callback.cc
+++ b/src/messaging/messages_change_callback.cc
@@ -63,7 +63,7 @@ MessagesChangeCallback::~MessagesChangeCallback() {
MessagePtrVector MessagesChangeCallback::filterMessages(tizen::AbstractFilterPtr filter,
const MessagePtrVector& source_messages,
const int service_id) {
- ScopeLogger("sourceMessages.size() = %d filter %s", source_messages.size(),
+ ScopeLogger("sourceMessages.size() = %zu filter %s", source_messages.size(),
(filter ? "PRESENT" : "NULL"));
if (filter) {
@@ -94,7 +94,7 @@ MessagePtrVector MessagesChangeCallback::filterMessages(tizen::AbstractFilterPtr
LoggerD("}");
}
- LoggerD("returning matching %d of %d messages", filtered_messages.size(),
+ LoggerD("returning matching %zu of %zu messages", filtered_messages.size(),
source_messages.size());
return filtered_messages;
} else {
@@ -104,7 +104,7 @@ MessagePtrVector MessagesChangeCallback::filterMessages(tizen::AbstractFilterPtr
}
void MessagesChangeCallback::added(const MessagePtrVector& msgs) {
- ScopeLogger("event: msgs.size() = %d", msgs.size());
+ ScopeLogger("event: msgs.size() = %zu", msgs.size());
if (!m_is_act) {
return;
}
@@ -123,14 +123,14 @@ void MessagesChangeCallback::added(const MessagePtrVector& msgs) {
for_each(filtered_msgs.begin(), filtered_msgs.end(), each);
- LoggerD("Calling:%s with:%d added messages", MESSAGESADDED, filtered_msgs.size());
+ LoggerD("Calling:%s with:%zu added messages", MESSAGESADDED, filtered_msgs.size());
m_callback_data.SetAction(MESSAGESADDED, picojson::value(array));
m_callback_data.AddAndPost(PostPriority::MEDIUM);
}
void MessagesChangeCallback::updated(const MessagePtrVector& msgs) {
- ScopeLogger("event: msgs.size() = %d", msgs.size());
+ ScopeLogger("event: msgs.size() = %zu", msgs.size());
if (!m_is_act) {
return;
}
@@ -149,14 +149,14 @@ void MessagesChangeCallback::updated(const MessagePtrVector& msgs) {
for_each(filtered_msgs.begin(), filtered_msgs.end(), each);
- LoggerD("Calling:%s with:%d updated messages", MESSAGESUPDATED, filtered_msgs.size());
+ LoggerD("Calling:%s with:%zu updated messages", MESSAGESUPDATED, filtered_msgs.size());
m_callback_data.SetAction(MESSAGESUPDATED, picojson::value(array));
m_callback_data.AddAndPost(PostPriority::LOW);
}
void MessagesChangeCallback::removed(const MessagePtrVector& msgs) {
- ScopeLogger("event: msgs.size() = %d", msgs.size());
+ ScopeLogger("event: msgs.size() = %zu", msgs.size());
if (!m_is_act) {
return;
}
@@ -176,7 +176,7 @@ void MessagesChangeCallback::removed(const MessagePtrVector& msgs) {
for_each(filtered_msgs.begin(), filtered_msgs.end(), each);
- LoggerD("Calling:%s with:%d removed messages", MESSAGESREMOVED, filtered_msgs.size());
+ LoggerD("Calling:%s with:%zu removed messages", MESSAGESREMOVED, filtered_msgs.size());
m_callback_data.SetAction(MESSAGESREMOVED, picojson::value(array));
m_callback_data.AddAndPost(PostPriority::LAST);
diff --git a/src/messaging/messaging.gyp b/src/messaging/messaging.gyp
index 7edb5a62..620dbb73 100644
--- a/src/messaging/messaging.gyp
+++ b/src/messaging/messaging.gyp
@@ -15,7 +15,6 @@
'msg-service',
'email-service',
'dbus-1',
- 'dbus-glib-1',
'capi-system-info',
'ecore',
'ecore-file',
diff --git a/src/messaging/messaging_api.js b/src/messaging/messaging_api.js
index 53d4c61f..d46536e4 100755
--- a/src/messaging/messaging_api.js
+++ b/src/messaging/messaging_api.js
@@ -213,9 +213,7 @@ function Message(type, data) {
return _internal.folderId;
},
set: function(value) {
- if (value instanceof InternalValues_) {
- _internal.folderId = value.folderId;
- }
+ if (value instanceof InternalValues_) _internal.folderId = value.folderId;
},
enumerable: true
});
@@ -299,9 +297,8 @@ function Message(type, data) {
return _internal.body;
},
set: function(value) {
- if (value instanceof InternalValues_) {
+ if (value instanceof InternalValues_)
_internal.body = new MessageBody(value.body);
- }
if (value instanceof MessageBody) _internal.body = value;
},
enumerable: true
@@ -363,9 +360,8 @@ function Message(type, data) {
return _internal.inResponseTo;
},
set: function(value) {
- if (value instanceof InternalValues_) {
+ if (value instanceof InternalValues_)
_internal.inResponseTo = value.inResponseTo;
- }
},
enumerable: true
});
@@ -510,9 +506,7 @@ function MessageBody(data) {
return _internal.messageId;
},
set: function(value) {
- if (value instanceof InternalValues_) {
- _internal.messageId = value.messageId;
- }
+ if (value instanceof InternalValues_) _internal.messageId = value.messageId;
},
enumerable: true
});
@@ -600,9 +594,7 @@ function MessageAttachment(first, second) {
return _internal.messageId;
},
set: function(value) {
- if (value instanceof InternalValues_) {
- _internal.messageId = value.messageId;
- }
+ if (value instanceof InternalValues_) _internal.messageId = value.messageId;
},
enumerable: true
});
@@ -647,10 +639,10 @@ function Messaging() {}
/**
* Gets the messaging service of a given type for a given account.
* @param {!MessageServiceTag} messageServiceType Type of the services to be retrieved.
- * @param {!MessageServiceArraySuccessCallback} successCallback Callback function
- * that is called when the services are successfully retrieved.
- * @param {ErrorCallback} errorCallback Callback function that is called
- * when an error occurs.
+ * @param {!MessageServiceArraySuccessCallback} successCallback Callback function that
+ * is called when the services are successfully retrieved.
+ * @param {ErrorCallback} errorCallback Callback function that is called when
+ * an error occurs.
*/
Messaging.prototype.getMessageServices = function() {
var args = validator_.validateArgs(arguments, [
diff --git a/src/messaging/messaging_instance.cc b/src/messaging/messaging_instance.cc
index 2cf41a50..91578660 100644
--- a/src/messaging/messaging_instance.cc
+++ b/src/messaging/messaging_instance.cc
@@ -20,6 +20,7 @@
#include <sstream>
#include <stdexcept>
+#include "common/filesystem/filesystem_provider.h"
#include "common/logger.h"
#include "common/tools.h"
@@ -203,6 +204,18 @@ void MessagingInstance::MessageServiceSendMessage(const picojson::value& args,
picojson::object data = args.get<picojson::object>();
picojson::value v_message = data.at(SEND_MESSAGE_ARGS_MESSAGE);
+
+ bool has_attachments = v_message.get("hasAttachment").get<bool>();
+ if (has_attachments) {
+ const auto& attachments = v_message.get("attachments").get<std::vector<picojson::value>>();
+ for (const auto& att : attachments) {
+ const auto& attachment_path = att.get("filePath").get<std::string>();
+ const auto& attachment_real_path =
+ common::FilesystemProvider::Create().GetRealPath(attachment_path);
+ CHECK_STORAGE_ACCESS(attachment_real_path, &out);
+ }
+ }
+
const double callbackId = args.get(JSON_CALLBACK_ID).get<double>();
auto json = std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
diff --git a/src/messaging/messaging_util.cc b/src/messaging/messaging_util.cc
index 5884f0d4..d7e6f32f 100644
--- a/src/messaging/messaging_util.cc
+++ b/src/messaging/messaging_util.cc
@@ -36,6 +36,7 @@
#include "common/logger.h"
#include "common/platform_exception.h"
#include "common/scope_exit.h"
+#include "common/tools.h"
#include "tizen/tizen.h"
using common::ErrorCode;
@@ -271,6 +272,7 @@ PlatformResult MessagingUtil::loadFileContentToString(const std::string& file_pa
std::string* result) {
ScopeLogger();
std::ifstream input_file;
+
input_file.open(file_path, std::ios::in);
if (input_file.is_open()) {
@@ -284,6 +286,7 @@ PlatformResult MessagingUtil::loadFileContentToString(const std::string& file_pa
input_file.close();
*result = ConvertToUtf8(file_path, outString);
} else {
+ LoggerW("open() error: %s", common::tools::GetErrorString(errno).c_str());
std::stringstream ss_error_msg;
ss_error_msg << "Failed to open file: " << file_path;
return LogAndCreateResult(ErrorCode::IO_ERR, ss_error_msg.str().c_str());
diff --git a/src/messaging/short_message_manager.cc b/src/messaging/short_message_manager.cc
index d1fc95ce..069a6863 100644
--- a/src/messaging/short_message_manager.cc
+++ b/src/messaging/short_message_manager.cc
@@ -53,7 +53,7 @@ static gboolean sendMessageCompleteCB(void* user_data) {
} else {
std::shared_ptr<Message> message = callback->getMessage();
- LoggerD("Calling success callback with: %d recipients", message->getTO().size());
+ LoggerD("Calling success callback with: %zu recipients", message->getTO().size());
std::vector<picojson::value> recipients;
auto addToRecipients = [&recipients](std::string& e) -> void {
@@ -393,7 +393,7 @@ PlatformResult ShortMsgManager::callProperEventMessages(EventMessages* event,
msg_storage_change_type_t storageChangeType,
ShortMsgManager* shortMsgManager) {
ScopeLogger(
- "event.items.size()=%d event.removed_conversations.size()=%d"
+ "event.items.size()=%zu event.removed_conversations.size()=%zu"
" sChangeType:%d",
event->items.size(), event->removed_conversations.size(), storageChangeType);
@@ -435,17 +435,17 @@ PlatformResult ShortMsgManager::callProperEventMessages(EventMessages* event,
cur_conv->getConversationId(), cur_conv->getLastMessageId());
}
- LoggerD("num conversations:all=%d added=%d update=%d", eventConv->items.size(),
+ LoggerD("num conversations:all=%zu added=%zu update=%zu", eventConv->items.size(),
added_conv.size(), updated_conv.size());
if (false == added_conv.empty()) {
- LoggerD("%d new conversations, calling onConversationAdded", added_conv.size());
+ LoggerD("%zu new conversations, calling onConversationAdded", added_conv.size());
eventConv->items = added_conv;
ChangeListenerContainer::getInstance().callConversationAdded(eventConv);
}
if (false == updated_conv.empty()) {
- LoggerD("%d updated conversation, calling onConversationUpdated", updated_conv.size());
+ LoggerD("%zu updated conversation, calling onConversationUpdated", updated_conv.size());
eventConv->items = updated_conv;
ChangeListenerContainer::getInstance().callConversationUpdated(eventConv);
}
@@ -535,7 +535,7 @@ void ShortMsgManager::storage_change_cb(msg_handle_t handle,
for (int i = 0; i < pMsgIdList->nCount; ++i) {
const msg_message_id_t& msg_id = pMsgIdList->msgIdList[i];
- LoggerD("pMsgIdList[%d] = %d", i, msg_id);
+ LoggerD("pMsgIdList[%d] = %u", i, msg_id);
std::map<int, MessagePtr>::iterator it = cur_rem_msgs.find(msg_id);
if (it != cur_rem_msgs.end()) {
@@ -761,7 +761,7 @@ void ShortMsgManager::updateMessages(MessagesCallbackUserData* callback) {
return;
}
- LoggerD("messages to update: %d", callback->getMessages().size());
+ LoggerD("messages to update: %zu", callback->getMessages().size());
{
std::lock_guard<std::mutex> lock(m_mutex);
@@ -849,7 +849,7 @@ PlatformResult ShortMsgManager::getMessage(int msg_id, msg_struct_t* out_msg) {
PlatformResult ShortMsgManager::getConversationsForMessages(
MessagePtrVector messages, msg_storage_change_type_t storageChangeType,
ConversationPtrVector* result, ShortMsgManager* shortMsgManager) {
- ScopeLogger("messages.size()=%d storageChangeType=%d", messages.size(), storageChangeType);
+ ScopeLogger("messages.size()=%zu storageChangeType=%d", messages.size(), storageChangeType);
std::unordered_set<int> unique_conv_ids;
ConversationPtrVector convs;
@@ -942,7 +942,7 @@ void ShortMsgManager::findMessages(FindMsgCallbackUserData* callback) {
if (callback->IsError()) {
LoggerD("Calling error callback");
} else {
- LoggerD("Calling success callback with %d messages:", callback->getMessages().size());
+ LoggerD("Calling success callback with %zu messages:", callback->getMessages().size());
std::vector<picojson::value> response;
auto messages = callback->getMessages();
@@ -1072,7 +1072,7 @@ void ShortMsgManager::removeConversations(ConversationCallbackData* callback) {
ConversationPtr conv = (*it);
msg_thread_id_t conv_id = conv->getConversationId();
- LoggerD("[%d] MessageConversation(%p) conv_id:%d", conv_index, conv.get(), conv_id);
+ LoggerD("[%d] MessageConversation(%p) conv_id:%u", conv_index, conv.get(), conv_id);
msg_struct_list_s conv_view_list;
error = msg_get_conversation_view_list(handle, (msg_thread_id_t)conv_id, &conv_view_list);
@@ -1088,14 +1088,14 @@ void ShortMsgManager::removeConversations(ConversationCallbackData* callback) {
LoggerD(
"[%d] message[%d] msg_id:%d,"
- "saved MessageConversation(%p) with conv_id:%d",
+ "saved MessageConversation(%p) with conv_id:%u",
conv_index, msg_index, cur_msg_id, conv.get(), conv_id);
} else {
LoggerE("[%d] Couldn't get msg_id, error: %s!", error, get_error_message(error));
}
}
} else {
- LoggerE("[%d] Couldn' get conversation view list for conv_id:%d error: %d", conv_index,
+ LoggerE("[%d] Couldn' get conversation view list for conv_id:%u error: %d", conv_index,
conv_id, error);
}
@@ -1139,12 +1139,12 @@ ShortMsgManager::ShortMsgManager() : m_msg_handle(NULL) {
ShortMsgManager::~ShortMsgManager() {
ScopeLogger();
- LoggerD("m_sms_removed_messages.size() = %d", m_sms_removed_messages.size());
- LoggerD("m_mms_removed_messages.size() = %d", m_mms_removed_messages.size());
- LoggerD("m_sms_removed_msg_id_conv_id_map.size() = %d", m_sms_removed_msg_id_conv_id_map.size());
- LoggerD("m_sms_removed_conv_id_object_map.size() = %d", m_sms_removed_conv_id_object_map.size());
- LoggerD("m_mms_removed_msg_id_conv_id_map.size() = %d", m_mms_removed_msg_id_conv_id_map.size());
- LoggerD("m_mms_removed_conv_id_object_map.size() = %d", m_mms_removed_conv_id_object_map.size());
+ LoggerD("m_sms_removed_messages.size() = %zu", m_sms_removed_messages.size());
+ LoggerD("m_mms_removed_messages.size() = %zu", m_mms_removed_messages.size());
+ LoggerD("m_sms_removed_msg_id_conv_id_map.size() = %zu", m_sms_removed_msg_id_conv_id_map.size());
+ LoggerD("m_sms_removed_conv_id_object_map.size() = %zu", m_sms_removed_conv_id_object_map.size());
+ LoggerD("m_mms_removed_msg_id_conv_id_map.size() = %zu", m_mms_removed_msg_id_conv_id_map.size());
+ LoggerD("m_mms_removed_conv_id_object_map.size() = %zu", m_mms_removed_conv_id_object_map.size());
}
std::string ShortMsgManager::getMessageStatus(int id) {
ScopeLogger();
diff --git a/src/networkbearerselection/networkbearerselection_instance.cc b/src/networkbearerselection/networkbearerselection_instance.cc
index ea339722..a88cecc0 100644
--- a/src/networkbearerselection/networkbearerselection_instance.cc
+++ b/src/networkbearerselection/networkbearerselection_instance.cc
@@ -110,7 +110,13 @@ void NetworkBearerSelectionInstance::NetworkBearerSelectionRequestRouteToHost(
NetworkBearerSelectionManager::GetInstance()->requestRouteToHost(domain_name, response);
};
- common::TaskQueue::GetInstance().Async(request);
+ // The RequestRouteToHost has to be executed in the main thread because of Native API
+ // implementation. The Web API implementation of NBSManager class has a global connection_h
+ // handle, which is used in every Request() method.
+ // However, the Native implementation uses std::thread_local-like variables, thus
+ // an execution of RequestRouteToHost() in thread different than main thread results in returning
+ // an error from C-API.
+ common::TaskQueue::GetInstance().ScheduleWorkInMainThread(request);
ReportSuccess(out);
}
@@ -155,7 +161,13 @@ void NetworkBearerSelectionInstance::NetworkBearerSelectionReleaseRouteToHost(
NetworkBearerSelectionManager::GetInstance()->releaseRouteToHost(domain_name, response);
};
- common::TaskQueue::GetInstance().Async(release);
+ // The ReleaseRouteToHost has to be executed in the main thread because of Native API
+ // implementation. The Web API implementation of NBSManager class has a global connection_h
+ // handle, which is used in every Request() method.
+ // However, the Native implementation uses std::thread_local-like variables, thus
+ // an execution of RequestRouteToHost/ReleaseRouteToHost() in thread different than main thread
+ // results in returning an error from C-API.
+ common::TaskQueue::GetInstance().ScheduleWorkInMainThread(release);
ReportSuccess(out);
}
diff --git a/src/networkbearerselection/networkbearerselection_manager.cc b/src/networkbearerselection/networkbearerselection_manager.cc
index b6206f46..33ec396f 100644
--- a/src/networkbearerselection/networkbearerselection_manager.cc
+++ b/src/networkbearerselection/networkbearerselection_manager.cc
@@ -17,6 +17,7 @@
#include "networkbearerselection_manager.h"
#include "common/logger.h"
#include "common/scope_exit.h"
+#include "common/task-queue.h"
#include <arpa/inet.h>
#include <netdb.h>
@@ -183,7 +184,8 @@ void NetworkBearerSelectionManager::callResultCallback(const ReplyCallback& repl
const PlatformResult result) {
ScopeLogger();
- std::thread(reply, result).detach();
+ auto reply_wrapper = [=] { reply(result); };
+ common::TaskQueue::GetInstance().Async(reply_wrapper);
}
void NetworkBearerSelectionManager::requestRouteToHost(const std::string& domain_name,
@@ -278,25 +280,26 @@ bool NetworkBearerSelectionManager::removeDomainRoute(
}
int ai_family = iter->second;
+ connection_address_family_e address_family = CONNECTION_ADDRESS_FAMILY_IPV4;
+
if (AF_INET == ai_family) {
LoggerD("IPv4 address");
- ret = connection_remove_route(m_connection_handle_, interface_name, domain_name);
} else if (AF_INET6 == ai_family) {
LoggerD("IPv6 address");
- ret = connection_profile_get_gateway_address(m_profile_handle_, CONNECTION_ADDRESS_FAMILY_IPV6,
- &gateway);
-
- if (CONNECTION_ERROR_NONE != ret) {
- LoggerE("Failed to get gateway");
- return false;
- }
-
- ret = connection_remove_route_ipv6(m_connection_handle_, interface_name, domain_name, gateway);
+ address_family = CONNECTION_ADDRESS_FAMILY_IPV6;
} else {
LoggerE("Incorrect family address");
return false;
}
+ ret = connection_profile_get_gateway_address(m_profile_handle_, address_family, &gateway);
+ if (CONNECTION_ERROR_NONE != ret) {
+ LoggerE("Failed to get gateway");
+ return false;
+ }
+ ret = connection_remove_route_entry(m_connection_handle_, address_family, interface_name,
+ domain_name, gateway);
+
if (CONNECTION_ERROR_NONE != ret) {
LoggerE("Failed to remove route");
return false;
@@ -407,23 +410,27 @@ bool NetworkBearerSelectionManager::registerStateChangeListener(const std::strin
return false;
}
+ connection_address_family_e address_family = CONNECTION_ADDRESS_FAMILY_IPV4;
+
if (AF_INET == serv_info->ai_family) {
- LoggerD("IPv4 add route");
- ret = connection_add_route(m_connection_handle_, interface_name, host_addr_ptr.get());
+ LoggerD("IPv4 address");
+ } else if (AF_INET6 == serv_info->ai_family) {
+ LoggerD("IPv6 address");
+ address_family = CONNECTION_ADDRESS_FAMILY_IPV6;
} else {
- LoggerD("IPv6 add route");
- ret = connection_profile_get_gateway_address(m_profile_handle_, CONNECTION_ADDRESS_FAMILY_IPV6,
- &gateway);
-
- if (CONNECTION_ERROR_NONE != ret) {
- LoggerE("Error while getting gateway address %d", ret);
- return false;
- }
+ LoggerE("Incorrect family address");
+ return false;
+ }
- ret = connection_add_route_ipv6(m_connection_handle_, interface_name, host_addr_ptr.get(),
- gateway);
+ ret = connection_profile_get_gateway_address(m_profile_handle_, address_family, &gateway);
+ if (CONNECTION_ERROR_NONE != ret) {
+ LoggerE("Failed to get gateway");
+ return false;
}
+ ret = connection_add_route_entry(m_connection_handle_, address_family, interface_name,
+ host_addr_ptr.get(), gateway);
+
if (CONNECTION_ERROR_NONE != ret) {
LoggerE("Adding route failed");
return false;
diff --git a/src/nfc/nfc_adapter.cc b/src/nfc/nfc_adapter.cc
index f1725f3a..65c87c41 100644
--- a/src/nfc/nfc_adapter.cc
+++ b/src/nfc/nfc_adapter.cc
@@ -436,7 +436,7 @@ PlatformResult NFCAdapter::SetCardEmulationMode(const std::string& mode) {
if (result.IsError()) {
return result;
}
- LoggerD("Card emulation mode value: %x", (int)new_mode);
+ LoggerD("Card emulation mode value: %x", (unsigned)new_mode);
std::string current_mode = "";
result = GetCardEmulationMode(&current_mode);
@@ -498,7 +498,7 @@ PlatformResult NFCAdapter::SetActiveSecureElement(std::string element) {
LoggerD("Error: %s", result.message().c_str());
return result;
}
- LoggerD("Secure element type value: %x", (int)new_type);
+ LoggerD("Secure element type value: %x", (unsigned)new_type);
std::string current_type = "";
result = GetActiveSecureElement(&current_type);
@@ -947,7 +947,7 @@ static void tagEventCallback(nfc_discovered_type_e type, nfc_tag_h tag, void* /*
obj.insert(make_pair("action", picojson::value("ondetach")));
NFCAdapter::GetInstance()->RespondAsync(event.serialize().c_str());
} else { // ERROR - should never happen
- LoggerE("Invalid NFC discovered type: %d (%x)", type, type);
+ LoggerE("Invalid NFC discovered type: %d (%x)", type, (unsigned)type);
}
}
@@ -1554,7 +1554,7 @@ PlatformResult NFCAdapter::SetPreferredApp() {
if (aids.empty()) {
return LogAndCreateResult(ErrorCode::ABORT_ERR, "No AID registered");
}
- LoggerD("Found %d AIDs", aids.size());
+ LoggerD("Found %zu AIDs", aids.size());
int ret = nfc_se_set_preferred_handler();
if (ret != NFC_ERROR_NONE) {
diff --git a/src/nfc/nfc_api.js b/src/nfc/nfc_api.js
index 5eef7c29..851ee585 100644
--- a/src/nfc/nfc_api.js
+++ b/src/nfc/nfc_api.js
@@ -274,9 +274,9 @@ function NFCAdapter() {
NFCAdapter.prototype.setPowered = function() {
privUtils_.warn(
- 'DEPRECATION WARNING: setPowered() is deprecated and ' +
- 'will be removed from next release. Let the user turn NFC on/off ' +
- 'through the Settings application instead.'
+ 'DEPRECATION WARNING: setPowered() is deprecated and will be removed from ' +
+ 'next release. Let the user turn NFC on/off through the Settings ' +
+ 'application instead.'
);
var args = validator_.validateArgs(arguments, [
diff --git a/src/nfc/nfc_util.cc b/src/nfc/nfc_util.cc
index de51aaac..e91e1a1f 100644
--- a/src/nfc/nfc_util.cc
+++ b/src/nfc/nfc_util.cc
@@ -221,7 +221,7 @@ PlatformResult NFCUtil::ToStringCardEmulationMode(const nfc_se_card_emulation_mo
break;
default:
return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "No Match Card Emulation mode",
- ("No Match Card Emulation mode: %x", card_mode));
+ ("No Match Card Emulation mode: %x", (unsigned)card_mode));
}
return PlatformResult(ErrorCode::NO_ERROR);
}
@@ -254,7 +254,7 @@ PlatformResult NFCUtil::ToStringSecureElementType(const nfc_se_type_e se_type, s
break;
default:
return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "No Match Secure Element Type",
- ("No Match Secure Element Type: %x", se_type));
+ ("No Match Secure Element Type: %x", (unsigned)se_type));
}
return PlatformResult(ErrorCode::NO_ERROR);
}
diff --git a/src/notification/common_notification.cc b/src/notification/common_notification.cc
index 52cc10be..1f824937 100644
--- a/src/notification/common_notification.cc
+++ b/src/notification/common_notification.cc
@@ -23,6 +23,7 @@
#include "common/filesystem/filesystem_provider.h"
#include "common/logger.h"
#include "common/scope_exit.h"
+#include "common/tools.h"
namespace extension {
namespace notification {
@@ -1080,6 +1081,8 @@ PlatformResult CommonNotification::SetPathFromJson(const picojson::value& noti_v
const std::string& value_str = FromJson<std::string>(noti_obj, key.c_str());
std::string real_path = FilesystemProvider::Create().GetRealPath(value_str);
+ CHECK_STORAGE_ACCESS_AND_RETURN(real_path);
+
PlatformResult status = SetImage(noti_handle, type, real_path);
CHECK_ERROR(status);
}
@@ -1314,6 +1317,8 @@ PlatformResult CommonNotification::SetPathsArrayFromJson(const picojson::value&
const std::string& text = JsonCast<std::string>(item);
std::string real_path = FilesystemProvider::Create().GetRealPath(text);
+ CHECK_STORAGE_ACCESS_AND_RETURN(real_path);
+
PlatformResult status = SetImage(noti_handle, map.at(idx), real_path);
CHECK_ERROR(status);
diff --git a/src/package/package_api.js b/src/package/package_api.js
index 9879bc51..fb89be00 100644
--- a/src/package/package_api.js
+++ b/src/package/package_api.js
@@ -14,72 +14,54 @@
* limitations under the License.
*/
-var JSON_ = xwalk.JSON;
var validator_ = xwalk.utils.validator;
var types_ = validator_.Types;
+var native_ = new xwalk.utils.NativeManager(extension);
var callbackId = 0;
var callbacks = {};
-var infoEventListenerId = -1;
-
-function invokeListener(result) {
- if (result.listener === 'infoEvent') {
- var listener = callbacks[infoEventListenerId];
- listener(result);
+var listener;
+var PACKAGE_INFO_LISTENER_ID = 'PackageInfoListener';
+var PACKAGE_PROGRESS_LISTENER_ID = 'PackageProgressListener_';
+
+function PackageInfoChangeCallback(result) {
+ if (result.status == 'installed') {
+ listener.oninstalled(new PackageInformation(result.info));
+ } else if (result.status == 'updated') {
+ listener.onupdated(new PackageInformation(result.info));
+ } else if (result.status == 'uninstalled') {
+ listener.onuninstalled(result.id);
}
}
-extension.setMessageListener(function(json) {
- var result = JSON_.parse(json);
-
- if (result.hasOwnProperty('listener')) {
- setTimeout(function() {
- invokeListener(result);
- }, 0);
- } else {
- var callback = callbacks[result['callbackId']];
- setTimeout(function() {
- callback(result);
- }, 0);
- }
-});
-
-function nextCallbackId() {
- return callbackId++;
-}
-
-function callNative(cmd, args) {
- var json = { cmd: cmd, args: args };
- var argjson = JSON_.stringify(json);
- var resultString = extension.internal.sendSyncMessage(argjson);
- var result = JSON_.parse(resultString);
-
- if (typeof result !== 'object') {
- throw new WebAPIException(WebAPIException.UNKNOWN_ERR);
- }
-
- if (result['status'] == 'success') {
- if (undefined !== result['result']) {
- return result['result'];
- }
- return true;
- } else if (result['status'] == 'error') {
+function PackageProgressCallback(result) {
+ if (result.status == 'progress') {
+ callbacks[result['progressCallbackId']].progressCallback.onprogress(
+ result.id,
+ result.progress
+ );
+ } else if (result.status == 'complete') {
+ callbacks[result['progressCallbackId']].progressCallback.oncomplete(result.id);
+ delete callbacks[result['progressCallbackId']];
+ native_.removeListener(
+ PACKAGE_PROGRESS_LISTENER_ID + result['progressCallbackId']
+ );
+ } else if (result.status == 'error') {
var err = result['error'];
if (err) {
- throw new WebAPIException(err);
+ callbacks[result['progressCallbackId']].errorCallback(
+ new WebAPIException(err)
+ );
+ delete callbacks[result['progressCallbackId']];
+ native_.removeListener(
+ PACKAGE_PROGRESS_LISTENER_ID + result['progressCallbackId']
+ );
}
- return false;
}
}
-function callNativeWithCallback(cmd, args, callback) {
- if (callback) {
- var id = nextCallbackId();
- args['callbackId'] = id;
- callbacks[id] = callback;
- }
-
- return callNative(cmd, args);
+function nextCallbackId() {
+ return callbackId++;
}
function SetReadOnlyProperty(obj, n, v) {
@@ -119,11 +101,12 @@ function PackageInformation(obj) {
set: function() {},
get: function() {
if (undefined === totalSize) {
- try {
- totalSize = callNative('PackageManager_getTotalSize', {
- id: this.id
- });
- } catch (e) {
+ var result = native_.callSync('PackageManager_getTotalSize', {
+ id: this.id
+ });
+ if (native_.isSuccess(result)) {
+ totalSize = native_.getResultObject(result);
+ } else {
totalSize = -1;
}
}
@@ -136,9 +119,12 @@ function PackageInformation(obj) {
set: function() {},
get: function() {
if (undefined === dataSize) {
- try {
- dataSize = callNative('PackageManager_getDataSize', { id: this.id });
- } catch (e) {
+ var result = native_.callSync('PackageManager_getDataSize', {
+ id: this.id
+ });
+ if (native_.isSuccess(result)) {
+ dataSize = native_.getResultObject(result);
+ } else {
dataSize = -1;
}
}
@@ -167,39 +153,30 @@ var PackageManagerInstall = function() {
}
]);
+ var progressCallbackId = nextCallbackId();
+ callbacks[progressCallbackId] = args;
+
var nativeParam = {
- packageFileURI: args.packageFileURI
+ packageFileURI: args.packageFileURI,
+ progressCallbackId: progressCallbackId
};
- try {
- var syncResult = callNativeWithCallback(
- 'PackageManager_install',
- nativeParam,
- function(result) {
- if (result.status == 'progress') {
- if (args.progressCallback.onprogress) {
- args.progressCallback.onprogress(result.id, result.progress);
- }
- } else if (result.status == 'complete') {
- if (args.progressCallback.oncomplete) {
- args.progressCallback.oncomplete(result.id);
- }
- } else if (result.status == 'error') {
- var err = result['error'];
- if (err) {
- args.errorCallback(new WebAPIException(err));
- return;
- }
- }
+ var result = native_.call('PackageManager_install', nativeParam, function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ delete callbacks[result['progressCallbackId']];
+ }
+ });
- if (result.status == 'complete' || result.status == 'error') {
- delete callbacks[result['callbackId']];
- }
- }
- );
- } catch (e) {
- throw e;
+ if (native_.isFailure(result)) {
+ delete callbacks[progressCallbackId];
+ throw native_.getErrorObject(result);
}
+
+ native_.addListener(
+ PACKAGE_PROGRESS_LISTENER_ID + progressCallbackId,
+ PackageProgressCallback
+ );
};
PackageManager.prototype.install = function(packageFileURI, progressCallback) {
@@ -222,39 +199,27 @@ var PackageManagerUninstall = function() {
}
]);
- var nativeParam = {
- id: args.id
- };
+ var progressCallbackId = nextCallbackId();
+ callbacks[progressCallbackId] = args;
- try {
- var syncResult = callNativeWithCallback(
- 'PackageManager_uninstall',
- nativeParam,
- function(result) {
- if (result.status == 'progress') {
- if (args.progressCallback.onprogress) {
- args.progressCallback.onprogress(result.id, result.progress);
- }
- } else if (result.status == 'complete') {
- if (args.progressCallback.oncomplete) {
- args.progressCallback.oncomplete(result.id);
- }
- } else if (result.status == 'error') {
- var err = result['error'];
- if (err) {
- args.errorCallback(new WebAPIException(err));
- return;
- }
- }
+ var nativeParam = { id: args.id, progressCallbackId: progressCallbackId };
- if (result.status == 'complete' || result.status == 'error') {
- delete callbacks[result['callbackId']];
- }
- }
- );
- } catch (e) {
- throw e;
+ var result = native_.call('PackageManager_uninstall', nativeParam, function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ delete callbacks[result['progressCallbackId']];
+ }
+ });
+
+ if (native_.isFailure(result)) {
+ delete callbacks[result['progressCallbackId']];
+ throw native_.getErrorObject(result);
}
+
+ native_.addListener(
+ PACKAGE_PROGRESS_LISTENER_ID + progressCallbackId,
+ PackageProgressCallback
+ );
};
PackageManager.prototype.uninstall = function(id, progressCallback) {
@@ -272,33 +237,21 @@ PackageManager.prototype.getPackagesInfo = function(successCallback, errorCallba
}
]);
- var nativeParam = {};
-
- try {
- var syncMsg = callNativeWithCallback(
- 'PackageManager_getPackagesInfo',
- nativeParam,
- function(result) {
- if (result.status == 'success') {
- for (var i = 0; i < result.informationArray.length; i++) {
- result.informationArray[i] = new PackageInformation(
- result.informationArray[i]
- );
- }
- args.successCallback(result.informationArray);
- } else if (result.status == 'error') {
- var err = result['error'];
- if (err) {
- args.errorCallback(new WebAPIException(err));
- return;
- }
- }
-
- delete callbacks[result['callbackId']];
+ var result = native_.call('PackageManager_getPackagesInfo', {}, function(result) {
+ if (native_.isSuccess(result)) {
+ for (var i = 0; i < result.informationArray.length; i++) {
+ result.informationArray[i] = new PackageInformation(
+ result.informationArray[i]
+ );
}
- );
- } catch (e) {
- throw e;
+ args.successCallback(result.informationArray);
+ } else if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ }
+ });
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
}
};
@@ -313,11 +266,11 @@ PackageManager.prototype.getPackageInfo = function() {
nativeParam['id'] = args.id;
}
- try {
- var syncResult = callNative('PackageManager_getPackageInfo', nativeParam);
- return new PackageInformation(syncResult);
- } catch (e) {
- throw e;
+ var result = native_.callSync('PackageManager_getPackageInfo', nativeParam);
+ if (native_.isSuccess(result)) {
+ return new PackageInformation(native_.getResultObject(result));
+ } else {
+ throw native_.getErrorObject(result);
}
};
@@ -330,48 +283,32 @@ PackageManager.prototype.setPackageInfoEventListener = function(eventCallback) {
}
]);
- var nativeParam = {};
+ var result = native_.callSync('PackageManager_setPackageInfoEventListener', {});
- try {
- var syncResult = callNativeWithCallback(
- 'PackageManager_setPackageInfoEventListener',
- nativeParam,
- function(result) {
- if (result.status == 'installed') {
- args.eventCallback.oninstalled(new PackageInformation(result.info));
- } else if (result.status == 'updated') {
- args.eventCallback.onupdated(new PackageInformation(result.info));
- } else if (result.status == 'uninstalled') {
- args.eventCallback.onuninstalled(result.id);
- }
- }
- );
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
- if (infoEventListenerId === -1) {
- infoEventListenerId = nativeParam.callbackId;
- } else {
- delete callbacks[infoEventListenerId];
- infoEventListenerId = nativeParam.callbackId;
- }
- } catch (e) {
- throw e;
+ if (!native_.isListenerSet(PACKAGE_INFO_LISTENER_ID)) {
+ native_.addListener(PACKAGE_INFO_LISTENER_ID, PackageInfoChangeCallback);
}
+ listener = args.eventCallback;
};
PackageManager.prototype.unsetPackageInfoEventListener = function() {
var nativeParam = {};
- try {
- var syncResult = callNative(
- 'PackageManager_unsetPackageInfoEventListener',
- nativeParam
- );
- if (syncResult === true) {
- delete callbacks[infoEventListenerId];
- infoEventListenerId = -1;
- }
- } catch (e) {
- throw e;
+ var result = native_.callSync(
+ 'PackageManager_unsetPackageInfoEventListener',
+ nativeParam
+ );
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+
+ if (native_.isListenerSet(PACKAGE_INFO_LISTENER_ID)) {
+ native_.removeListener(PACKAGE_INFO_LISTENER_ID);
}
};
diff --git a/src/package/package_instance.cc b/src/package/package_instance.cc
index d0a11470..a1ca8888 100644
--- a/src/package/package_instance.cc
+++ b/src/package/package_instance.cc
@@ -16,9 +16,11 @@
#include "package/package_instance.h"
+#include <glib.h>
#include <functional>
#include <string>
+#include "common/filesystem/filesystem_provider.h"
#include "common/logger.h"
#include "common/picojson.h"
#include "common/task-queue.h"
@@ -51,16 +53,16 @@ typedef enum _PackageThreadWorkType {
class PackageUserData {
public:
- PackageUserData(PackageInstance* ins, int id, PackageThreadWorkType task) {
+ PackageUserData(PackageInstance* ins, int id, PackageThreadWorkType task,
+ int progress_callback_id = 0)
+ : instance_(ins), callback_id_(id), work_(task), progress_callback_id_(progress_callback_id) {
ScopeLogger();
- instance_ = ins;
- callback_id_ = id;
- work_ = task;
}
PackageInstance* instance_;
int callback_id_;
PackageThreadWorkType work_;
+ int progress_callback_id_;
picojson::object data_;
};
typedef std::shared_ptr<PackageUserData> PackageUserDataPtr;
@@ -85,6 +87,10 @@ static gboolean PackageAfterWork(const PackageUserDataPtr& userData) {
ScopeLogger();
userData->data_["callbackId"] = picojson::value(static_cast<double>(userData->callback_id_));
+ if (PackageThreadWorkNone == userData->work_) {
+ userData->data_["progressCallbackId"] =
+ picojson::value(static_cast<double>(userData->progress_callback_id_));
+ }
picojson::value result = picojson::value(userData->data_);
common::Instance::PostMessage(userData->instance_, result.serialize().c_str());
@@ -150,7 +156,7 @@ static void PackageListenerCb(const char* type, const char* package,
}
picojson::object param;
- param["listener"] = picojson::value("infoEvent");
+ param["listenerId"] = picojson::value("PackageInfoListener");
LoggerD("Listener type: %d , state: %d, progress: %d", event_type, event_state, progress);
if (event_type == PACKAGE_MANAGER_EVENT_TYPE_INSTALL &&
@@ -280,7 +286,9 @@ void PackageInstance::InvokeCallback(int request_id, picojson::object& param) {
int callback_id = callbacks_map_[request_id];
- param["callbackId"] = picojson::value(static_cast<double>(callback_id));
+ std::string listenerId = "PackageProgressListener_" + std::to_string(callback_id);
+ param["listenerId"] = picojson::value(listenerId);
+ param["progressCallbackId"] = picojson::value(static_cast<double>(callback_id));
picojson::value result = picojson::value(param);
Instance::PostMessage(this, result.serialize().c_str());
}
@@ -292,14 +300,20 @@ void PackageInstance::PackageManagerInstall(const picojson::value& args, picojso
CHECK_EXIST(args, "callbackId", out)
CHECK_EXIST(args, "packageFileURI", out)
+ CHECK_EXIST(args, "progressCallbackId", out)
int callback_id = static_cast<int>(args.get("callbackId").get<double>());
const std::string& packageFileURI =
convertUriToPath(args.get("packageFileURI").get<std::string>());
+ int progress_callback_id = static_cast<int>(args.get("progressCallbackId").get<double>());
+
+ const std::string real_path = common::FilesystemProvider::Create().GetRealPath(packageFileURI);
+
+ CHECK_STORAGE_ACCESS(real_path, &out);
if (!request_) {
LoggerE("package_manager_request_h is NULL");
- InvokeErrorCallbackAsync(callback_id,
+ InvokeErrorCallbackAsync(callback_id, progress_callback_id,
UnknownException("It is not allowed to install the package by "
"the platform or any other platform error occurs"));
return;
@@ -311,15 +325,16 @@ void PackageInstance::PackageManagerInstall(const picojson::value& args, picojso
if (ret == PACKAGE_MANAGER_ERROR_INVALID_PARAMETER) {
LoggerE("The package is not found at the specified location");
InvokeErrorCallbackAsync(
- callback_id, NotFoundException("The package is not found at the specified location"));
+ callback_id, progress_callback_id,
+ NotFoundException("The package is not found at the specified location"));
} else {
LoggerE("Failed to install package: %d (%s)", ret, get_error_message(ret));
- InvokeErrorCallbackAsync(callback_id,
+ InvokeErrorCallbackAsync(callback_id, progress_callback_id,
UnknownException("It is not allowed to install the package by "
"the platform or any other platform error occurs"));
}
} else {
- RegisterCallback(request_id, callback_id);
+ RegisterCallback(request_id, progress_callback_id);
}
ReportSuccess(out);
@@ -332,13 +347,15 @@ void PackageInstance::PackageManagerUninstall(const picojson::value& args, picoj
CHECK_EXIST(args, "callbackId", out)
CHECK_EXIST(args, "id", out)
+ CHECK_EXIST(args, "progressCallbackId", out)
int callback_id = static_cast<int>(args.get("callbackId").get<double>());
const std::string& id = args.get("id").get<std::string>();
+ int progress_callback_id = static_cast<int>(args.get("progressCallbackId").get<double>());
if (!request_) {
LoggerE("package_manager_request_h is NULL");
- InvokeErrorCallbackAsync(callback_id,
+ InvokeErrorCallbackAsync(callback_id, progress_callback_id,
UnknownException("It is not allowed to install the package by "
"the platform or any other platform error occurs"));
return;
@@ -350,11 +367,12 @@ void PackageInstance::PackageManagerUninstall(const picojson::value& args, picoj
if (ret == PACKAGE_MANAGER_ERROR_NO_SUCH_PACKAGE) {
LoggerE("The package is not found at the specified location");
InvokeErrorCallbackAsync(
- callback_id, NotFoundException("The package is not found at the specified location"));
+ callback_id, progress_callback_id,
+ NotFoundException("The package is not found at the specified location"));
} else {
LoggerE("Failed to get package info: %d (%s)", ret, get_error_message(ret));
InvokeErrorCallbackAsync(
- callback_id,
+ callback_id, progress_callback_id,
UnknownException("It is not allowed to get package information by the platform or "
"any other platform error occurs"));
}
@@ -366,11 +384,11 @@ void PackageInstance::PackageManagerUninstall(const picojson::value& args, picoj
if (ret != PACKAGE_MANAGER_ERROR_NONE) {
LoggerE("Failed to uninstall package: %d (%s)", ret, get_error_message(ret));
InvokeErrorCallbackAsync(
- callback_id,
+ callback_id, progress_callback_id,
UnknownException("It is not allowed to install the package by the platform or "
"any other platform error occurs"));
} else {
- RegisterCallback(request_id, callback_id);
+ RegisterCallback(request_id, progress_callback_id);
}
}
@@ -442,8 +460,6 @@ void PackageInstance::PackageManagerSetpackageinfoeventlistener(const picojson::
CHECK_PRIVILEGE_ACCESS(kPrivilegePackageInfo, &out);
- CHECK_EXIST(args, "callbackId", out)
-
if (is_package_info_listener_set_) {
LoggerD("Already set");
ReportSuccess(out);
@@ -501,12 +517,14 @@ void PackageInstance::PackageManagerUnsetpackageinfoeventlistener(const picojson
ReportSuccess(out);
}
-void PackageInstance::InvokeErrorCallbackAsync(int callback_id, const PlatformException& ex) {
+void PackageInstance::InvokeErrorCallbackAsync(int callback_id, int progress_callback_id,
+ const PlatformException& ex) {
ScopeLogger();
picojson::object param;
LogAndReportError(ex, param);
- PackageUserDataPtr userData(new PackageUserData(this, callback_id, PackageThreadWorkNone));
+ PackageUserDataPtr userData(
+ new PackageUserData(this, callback_id, PackageThreadWorkNone, progress_callback_id));
userData->data_ = param;
TaskQueue::GetInstance().Async<PackageUserData>(PackageAfterWork, userData);
}
diff --git a/src/package/package_instance.h b/src/package/package_instance.h
index 3ae7163b..772d4cb1 100644
--- a/src/package/package_instance.h
+++ b/src/package/package_instance.h
@@ -43,7 +43,8 @@ class PackageInstance : public common::ParsedInstance {
std::map<int, int> callbacks_map_; // <request_id, callbackId>
void RegisterCallback(int request_id, int callback_id);
- void InvokeErrorCallbackAsync(int callback_id, const common::PlatformException& ex);
+ void InvokeErrorCallbackAsync(int callback_id, int progress_callback_id,
+ const common::PlatformException& ex);
void PackageManagerInstall(const picojson::value& args, picojson::object& out);
void PackageManagerUninstall(const picojson::value& args, picojson::object& out);
diff --git a/src/power/power_api.js b/src/power/power_api.js
index 2c2a1858..7a93b53d 100755
--- a/src/power/power_api.js
+++ b/src/power/power_api.js
@@ -104,8 +104,8 @@ PowerManager.prototype.request = function() {
if (args.state === PowerScreenState.SCREEN_BRIGHT) {
privUtils_.warn(
- 'DEPRECATION WARNING: SCREEN_BRIGHT is deprecated ' +
- 'and will be removed from next release.'
+ 'DEPRECATION WARNING: SCREEN_BRIGHT is deprecated and will be removed ' +
+ 'from next release.'
);
}
@@ -247,8 +247,8 @@ PowerManager.prototype.restoreScreenBrightness = function() {
*/
PowerManager.prototype.turnScreenOn = function() {
privUtils_.warn(
- 'DEPRECATION WARNING: turnScreenOn() is deprecated ' +
- 'and will be removed from next release. Use request() instead.'
+ 'DEPRECATION WARNING: turnScreenOn() is deprecated and will be removed from ' +
+ 'next release. Use request() instead.'
);
var ret = native_.callSync('PowerManager_turnScreenOn', {});
@@ -262,8 +262,8 @@ PowerManager.prototype.turnScreenOn = function() {
*/
PowerManager.prototype.turnScreenOff = function() {
privUtils_.warn(
- 'DEPRECATION WARNING: turnScreenOff() is deprecated ' +
- 'and will be removed from next release. Use release() instead.'
+ 'DEPRECATION WARNING: turnScreenOff() is deprecated and will be removed from ' +
+ 'next release. Use release() instead.'
);
var ret = native_.callSync('PowerManager_turnScreenOff', {});
diff --git a/src/ppm/ppm_api.js b/src/ppm/ppm_api.js
index e6fa82a0..972b5818 100644
--- a/src/ppm/ppm_api.js
+++ b/src/ppm/ppm_api.js
@@ -21,6 +21,13 @@ var native_ = new xwalk.utils.NativeManager(extension);
function PPMManager() {}
+function RequestStatus(privilege, result_) {
+ Object.defineProperties(this, {
+ privilege: { value: privilege, writable: false },
+ result: { value: result_, writable: false }
+ });
+}
+
PPMManager.prototype.checkPermission = function() {
var args = validator_.validateArgs(arguments, [
{ name: 'privilege', type: types_.STRING }
@@ -39,6 +46,32 @@ PPMManager.prototype.checkPermission = function() {
return native_.getResultObject(result);
};
+PPMManager.prototype.checkPermissions = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'privileges', type: types_.ARRAY, values: types_.STRING }
+ ]);
+
+ var callArgs = {
+ privileges: args.privileges
+ };
+
+ var result = native_.callSync('PPMManager_checkPermissions', callArgs);
+
+ var data = [];
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ } else {
+ var obj = native_.getResultObject(result);
+
+ obj.forEach(function(o) {
+ data.push({ privilege: o.privilege, type: o.type });
+ });
+ }
+
+ return data;
+};
+
PPMManager.prototype.requestPermission = function() {
var args = validator_.validateArgs(arguments, [
{ name: 'privilege', type: types_.STRING },
@@ -65,5 +98,37 @@ PPMManager.prototype.requestPermission = function() {
}
};
+PPMManager.prototype.requestPermissions = function() {
+ var args = validator_.validateArgs(arguments, [
+ { name: 'privileges', type: types_.ARRAY, values: types_.STRING },
+ { name: 'successCallback', type: types_.FUNCTION },
+ { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+ ]);
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+ } else {
+ var data = [];
+ var obj = native_.getResultObject(result);
+
+ obj.forEach(function(o) {
+ data.push(new RequestStatus(o.privilege, o.result));
+ });
+ args.successCallback(data);
+ }
+ };
+
+ var callArgs = {
+ privileges: args.privileges
+ };
+
+ var result = native_.call('PPMManager_requestPermissions', callArgs, callback);
+
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+};
+
// Exports
exports = new PPMManager();
diff --git a/src/ppm/ppm_instance.cc b/src/ppm/ppm_instance.cc
index 7f419a32..039e4303 100644
--- a/src/ppm/ppm_instance.cc
+++ b/src/ppm/ppm_instance.cc
@@ -46,7 +46,9 @@ PPMInstance::PPMInstance() {
#define REGISTER(c, x) RegisterSyncHandler(c, std::bind(&PPMInstance::x, this, _1, _2));
REGISTER("PPMManager_checkPermission", checkPermission);
+ REGISTER("PPMManager_checkPermissions", checkPermissions);
REGISTER("PPMManager_requestPermission", requestPermission);
+ REGISTER("PPMManager_requestPermissions", requestPermissions);
#undef REGISTER
}
@@ -115,11 +117,11 @@ void PPMInstance::ResponseCallback(ppm_call_cause_e cause, ppm_request_result_e
picojson::value event = picojson::value(picojson::object());
picojson::object& obj = event.get<picojson::object>();
- obj.insert(std::make_pair("callbackId", picojson::value(data->callbackId)));
+ obj.emplace(std::make_pair("callbackId", picojson::value(data->callbackId)));
if (PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ANSWER == cause) {
- obj.insert(std::make_pair("result", picojson::value(CheckRequestResultToString(result))));
- obj.insert(std::make_pair("privilege", picojson::value(privilege)));
+ obj.emplace(std::make_pair("result", picojson::value(CheckRequestResultToString(result))));
+ obj.emplace(std::make_pair("privilege", picojson::value(privilege)));
} else {
LogAndReportError(
common::PlatformResult(common::ErrorCode::ABORT_ERR, "Get callback data failed"), &obj);
@@ -127,6 +129,40 @@ void PPMInstance::ResponseCallback(ppm_call_cause_e cause, ppm_request_result_e
common::Instance::PostMessage(data->_instance, event.serialize().c_str());
}
+void PPMInstance::ResponseMultipleCallback(ppm_call_cause_e cause,
+ const ppm_request_result_e* result,
+ const char** privileges, size_t privileges_count,
+ void* user_data) {
+ ScopeLogger();
+
+ std::unique_ptr<ResponseCallbackData> data{static_cast<ResponseCallbackData*>(user_data)};
+
+ picojson::value event = picojson::value(picojson::object());
+ picojson::object& obj = event.get<picojson::object>();
+
+ obj.emplace(std::make_pair("callbackId", picojson::value(data->callbackId)));
+
+ if (PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ANSWER == cause) {
+ picojson::value result_array = picojson::value(picojson::array());
+ picojson::array& array_obj = result_array.get<picojson::array>();
+ array_obj.reserve(privileges_count);
+
+ for (size_t i = 0; i < privileges_count; i++) {
+ picojson::value result_elem = picojson::value(picojson::object());
+ picojson::object& obj = result_elem.get<picojson::object>();
+ obj["privilege"] = picojson::value(privileges[i]);
+ obj["result"] = picojson::value(CheckRequestResultToString(result[i]));
+ array_obj.push_back(std::move(result_elem));
+ }
+ obj.emplace(std::make_pair("result", result_array));
+ } else {
+ LogAndReportError(
+ common::PlatformResult(common::ErrorCode::ABORT_ERR, "Get callback data failed"), &obj);
+ }
+
+ common::Instance::PostMessage(data->_instance, event.serialize().c_str());
+}
+
void PPMInstance::checkPermission(const picojson::value& args, picojson::object& out) {
ScopeLogger();
const std::string& privilege = args.get("privilege").get<std::string>();
@@ -145,6 +181,44 @@ void PPMInstance::checkPermission(const picojson::value& args, picojson::object&
ReportSuccess(picojson::value(CheckResultToString(result)), out);
}
+void PPMInstance::checkPermissions(const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+
+ const picojson::array& privileges = args.get("privileges").get<picojson::array>();
+ std::vector<const char*> privilege_array;
+ privilege_array.reserve(privileges.size());
+
+ for (auto iter = privileges.begin(); iter != privileges.end(); ++iter) {
+ privilege_array.push_back(iter->get<std::string>().c_str());
+ }
+
+ std::vector<ppm_check_result_e> results(privileges.size());
+ int ret = ppm_check_permissions(privilege_array.data(), privileges.size(), results.data());
+
+ if (PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE != ret) {
+ LogAndReportError(convertError(ret), &out,
+ ("checkPermission error: %d (%s)", ret, get_error_message(ret)));
+
+ return;
+ }
+
+ picojson::value result_array = picojson::value(picojson::array());
+ picojson::array& array_obj = result_array.get<picojson::array>();
+ array_obj.reserve(privileges.size());
+
+ for (size_t i = 0; i < privileges.size(); i++) {
+ picojson::value result_elem = picojson::value(picojson::object());
+ picojson::object& obj = result_elem.get<picojson::object>();
+
+ obj["privilege"] = picojson::value(privilege_array[i]);
+ obj["type"] = picojson::value(CheckResultToString(results[i]));
+
+ array_obj.push_back(std::move(result_elem));
+ }
+
+ ReportSuccess(result_array, out);
+}
+
void PPMInstance::requestPermission(const picojson::value& args, picojson::object& out) {
ScopeLogger();
@@ -169,5 +243,34 @@ void PPMInstance::requestPermission(const picojson::value& args, picojson::objec
ReportSuccess(out);
}
+void PPMInstance::requestPermissions(const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+
+ const double callback_id = args.get("callbackId").get<double>();
+ const picojson::array& privileges = args.get("privileges").get<picojson::array>();
+ std::vector<const char*> privilege_array;
+ privilege_array.reserve(privileges.size());
+
+ for (auto iter = privileges.begin(); iter != privileges.end(); ++iter) {
+ privilege_array.push_back(iter->get<std::string>().c_str());
+ }
+
+ ResponseCallbackData* user_data{new ResponseCallbackData()};
+ user_data->_instance = this;
+ user_data->callbackId = callback_id;
+
+ int ret = ppm_request_permissions(privilege_array.data(), privileges.size(),
+ ResponseMultipleCallback, static_cast<void*>(user_data));
+
+ if (PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE != ret) {
+ delete user_data;
+ LogAndReportError(convertError(ret), &out,
+ ("checkPermission error: %d (%s)", ret, get_error_message(ret)));
+ return;
+ }
+
+ ReportSuccess(out);
+}
+
} // namespace ppm
} // namespace extension
diff --git a/src/ppm/ppm_instance.h b/src/ppm/ppm_instance.h
index 9d1825ce..1df853d9 100644
--- a/src/ppm/ppm_instance.h
+++ b/src/ppm/ppm_instance.h
@@ -35,13 +35,18 @@ class PPMInstance : public common::ParsedInstance {
private:
void checkPermission(const picojson::value& args, picojson::object& out);
+ void checkPermissions(const picojson::value& args, picojson::object& out);
void requestPermission(const picojson::value& args, picojson::object& out);
+ void requestPermissions(const picojson::value& args, picojson::object& out);
static common::PlatformResult convertError(int err, const std::string& message = "");
static std::string CheckResultToString(ppm_check_result_e result);
static std::string CheckRequestResultToString(ppm_request_result_e result);
static void ResponseCallback(ppm_call_cause_e cause, ppm_request_result_e result,
const char* privilege, void* user_data);
+ static void ResponseMultipleCallback(ppm_call_cause_e cause, const ppm_request_result_e* result,
+ const char** privileges, size_t privileges_count,
+ void* user_data);
};
} // namespace ppm
diff --git a/src/preference/preference_manager.cc b/src/preference/preference_manager.cc
index ecd9665e..95c82eec 100644
--- a/src/preference/preference_manager.cc
+++ b/src/preference/preference_manager.cc
@@ -19,6 +19,7 @@
#include <thread>
#include "common/logger.h"
+#include "common/task-queue.h"
#include "common/tools.h"
#include "preference/preference_instance.h"
#include "preference/preference_manager.h"
@@ -173,7 +174,9 @@ common::TizenResult PreferenceManager::GetAll(const common::PostCallback& callba
callback(result, response);
};
- std::thread(get_all, callback).detach();
+ auto get_all_wrapper = [=] { get_all(callback); };
+
+ common::TaskQueue::GetInstance().Async(get_all_wrapper);
return common::TizenSuccess();
}
diff --git a/src/push/push_api.js b/src/push/push_api.js
index 4e4e3603..6bea2c9f 100644
--- a/src/push/push_api.js
+++ b/src/push/push_api.js
@@ -58,8 +58,8 @@ function PushManager() {
PushManager.prototype.registerService = function() {
privUtils_.warn(
- 'DEPRECATION WARNING: registerService() is deprecated ' +
- 'and will be removed from next release. Use register() instead.'
+ 'DEPRECATION WARNING: registerService() is deprecated and will be removed ' +
+ 'from next release. Use register() instead.'
);
var data = validator.validateArgs(arguments, [
{
@@ -123,8 +123,8 @@ PushManager.prototype.register = function() {
PushManager.prototype.unregisterService = function() {
privUtils_.warn(
- 'DEPRECATION WARNING: unregisterService() is deprecated ' +
- 'and will be removed from next release. Use unregister() instead.'
+ 'DEPRECATION WARNING: unregisterService() is deprecated and will be removed ' +
+ 'from next release. Use unregister() instead.'
);
var data = validator.validateArgs(arguments, [
{
@@ -187,8 +187,8 @@ PushManager.prototype.unregister = function() {
PushManager.prototype.connectService = function(notificationCallback) {
privUtils_.warn(
- 'DEPRECATION WARNING: connectService() is deprecated ' +
- 'and will be removed from next release. Use connect() instead.'
+ 'DEPRECATION WARNING: connectService() is deprecated and will be removed from ' +
+ 'next release. Use connect() instead.'
);
var data = validator.validateArgs(arguments, [
{
@@ -254,8 +254,8 @@ PushManager.prototype.connect = function(notificationCallback) {
PushManager.prototype.disconnectService = function() {
privUtils_.warn(
- 'DEPRECATION WARNING: disconnectService() is deprecated ' +
- 'and will be removed from next release. Use disconnect() instead.'
+ 'DEPRECATION WARNING: disconnectService() is deprecated and will be removed ' +
+ 'from next release. Use disconnect() instead.'
);
var ret = native.callSync('Push_disconnectService', {});
if (native.isFailure(ret)) {
diff --git a/src/radio/radio.gyp b/src/radio/radio.gyp
index 79d37d59..6c099001 100644
--- a/src/radio/radio.gyp
+++ b/src/radio/radio.gyp
@@ -25,9 +25,10 @@
['tizen == 1', {
'variables': {
'packages': [
+ 'capi-system-runtime-info',
'vconf',
'capi-media-radio',
- 'capi-system-runtime-info',
+ 'capi-media-sound-manager',
]
},
}],
diff --git a/src/radio/radio_manager.cc b/src/radio/radio_manager.cc
index 2e9ea1ea..9fe1b40b 100644
--- a/src/radio/radio_manager.cc
+++ b/src/radio/radio_manager.cc
@@ -88,24 +88,34 @@ PlatformResult CheckError(const std::string& str, int err) {
}
}
-string TranslateInterruptedCode(int code) {
- ScopeLogger();
-#define STRINGIFY(c) \
- case c: \
- return #c
- switch (code) {
- STRINGIFY(RADIO_INTERRUPTED_BY_MEDIA);
- STRINGIFY(RADIO_INTERRUPTED_BY_CALL);
- STRINGIFY(RADIO_INTERRUPTED_BY_EARJACK_UNPLUG);
- STRINGIFY(RADIO_INTERRUPTED_BY_RESOURCE_CONFLICT);
- STRINGIFY(RADIO_INTERRUPTED_BY_ALARM);
- STRINGIFY(RADIO_INTERRUPTED_BY_EMERGENCY);
- STRINGIFY(RADIO_INTERRUPTED_BY_RESUMABLE_MEDIA);
- STRINGIFY(RADIO_INTERRUPTED_BY_NOTIFICATION);
+string TranslateInterruptedCode(sound_stream_focus_change_reason_e reason) {
+ ScopeLogger();
+ switch (reason) {
+ case SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA:
+ return "RADIO_INTERRUPTED_BY_MEDIA";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_SYSTEM:
+ return "RADIO_INTERRUPTED_BY_SYSTEM";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_ALARM:
+ return "RADIO_INTERRUPTED_BY_ALARM";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_NOTIFICATION:
+ return "RADIO_INTERRUPTED_BY_NOTIFICATION";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_EMERGENCY:
+ return "RADIO_INTERRUPTED_BY_EMERGENCY";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION:
+ return "RADIO_INTERRUPTED_BY_VOICE_INFORMATION";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_RECOGNITION:
+ return "RADIO_INTERRUPTED_BY_VOICE_RECOGNITION";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_RINGTONE:
+ return "RADIO_INTERRUPTED_BY_RINGTONE";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_VOIP:
+ return "RADIO_INTERRUPTED_BY_VOIP";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_CALL:
+ return "RADIO_INTERRUPTED_BY_CALL";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA_EXTERNAL_ONLY:
+ return "RADIO_INTERRUPTED_BY_MEDIA_EXTERNAL_ONLY";
default:
return "UNKNOWN_INTERRUPTED_ERROR_CODE";
}
-#undef STRINGIFY
}
int TokHz(double frequency) {
@@ -185,26 +195,6 @@ void ScanStopCallback(void* user_data) {
delete data;
}
-void RadioInterruptedCallback(radio_interrupted_code_e code, void* user_data) {
- ScopeLogger();
-
- picojson::value event{picojson::object()};
- auto& obj = event.get<picojson::object>();
-
- obj.insert(std::make_pair("listenerId", picojson::value("FMRadio_Interrupted")));
-
- if (code == RADIO_INTERRUPTED_COMPLETED) {
- obj.insert(std::make_pair("action", picojson::value("oninterruptfinished")));
- } else {
- obj.insert(std::make_pair("action", picojson::value("oninterrupted")));
- obj.insert(std::make_pair("reason", picojson::value(TranslateInterruptedCode(code))));
- }
-
- FMRadioManager* manager = static_cast<FMRadioManager*>(user_data);
- common::TaskQueue::GetInstance().Async(
- std::bind(&FMRadioManager::PostMessage, manager, event.serialize()));
-}
-
void RadioAntennaCallback(runtime_info_key_e key, void* user_data) {
ScopeLogger();
@@ -225,6 +215,51 @@ void RadioAntennaCallback(runtime_info_key_e key, void* user_data) {
std::bind(&FMRadioManager::PostMessage, manager, event.serialize()));
}
+void SoundStreamFocusCallback(sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask,
+ sound_stream_focus_state_e focus_state,
+ sound_stream_focus_change_reason_e reason_for_change,
+ int sound_behavior, const char* additional_info, void* user_data) {
+ ScopeLogger("reason_for_change: %d", reason_for_change);
+
+ FMRadioManager* manager = static_cast<FMRadioManager*>(user_data);
+
+ picojson::value event{picojson::object()};
+ auto& obj = event.get<picojson::object>();
+
+ obj.insert(std::make_pair("listenerId", picojson::value("FMRadio_Interrupted")));
+
+ if (SOUND_STREAM_FOCUS_STATE_ACQUIRED != focus_state) {
+ LoggerD("Stopping radio");
+ const auto err_radio_stop = radio_stop(manager->GetRadioInstance());
+ if (RADIO_ERROR_NONE != err_radio_stop) {
+ LoggerE("Failed to stop radio: %d", err_radio_stop);
+ }
+
+ obj.insert(std::make_pair("action", picojson::value("oninterrupted")));
+ obj.insert(
+ std::make_pair("reason", picojson::value(TranslateInterruptedCode(reason_for_change))));
+ } else {
+ // As we stopped radio on first interrupt, we will release focus on second
+ LoggerD("Preparing to release focus");
+ auto release_focus = [manager]() {
+ ScopeLogger("Entered into asynchronous function, release_focus");
+ const auto sound_focus_err = sound_manager_release_focus(
+ manager->GetStreamInfo(), SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, NULL);
+ if (SOUND_MANAGER_ERROR_NONE != sound_focus_err) {
+ LoggerE("sound_manager_release_focus() failed: %d", sound_focus_err);
+ }
+ };
+ common::TaskQueue::GetInstance().Async(release_focus);
+
+ obj.insert(std::make_pair("action", picojson::value("oninterruptfinished")));
+ }
+
+ if (manager->IsInterruptedListenerSet()) {
+ common::TaskQueue::GetInstance().Async(
+ std::bind(&FMRadioManager::PostMessage, manager, event.serialize()));
+ }
+}
+
} // namespace
bool FMRadioManager::IsMuted() {
@@ -293,6 +328,18 @@ const char* FMRadioManager::GetState() {
}
}
+bool FMRadioManager::IsInterruptedListenerSet() {
+ return is_interrupted_listener_set;
+}
+
+radio_h FMRadioManager::GetRadioInstance() {
+ return radio_instance_;
+};
+
+sound_stream_info_h FMRadioManager::GetStreamInfo() {
+ return stream_info_;
+}
+
PlatformResult FMRadioManager::SetFrequency(double frequency) {
ScopeLogger();
return CheckError("radio_set_frequency", radio_set_frequency(radio_instance_, TokHz(frequency)));
@@ -328,7 +375,11 @@ double FMRadioManager::GetSignalStrength() {
}
FMRadioManager::FMRadioManager(RadioInstance& instance)
- : instance_(instance), radio_instance_(nullptr), scan_data(nullptr) {
+ : instance_(instance),
+ radio_instance_(nullptr),
+ scan_data(nullptr),
+ stream_info_(nullptr),
+ is_interrupted_listener_set(false) {
ScopeLogger();
const auto err = radio_create(&radio_instance_);
@@ -337,6 +388,13 @@ FMRadioManager::FMRadioManager(RadioInstance& instance)
LoggerE("radio_create() failed: %d", err);
radio_instance_ = nullptr;
}
+
+ const auto err_sound = sound_manager_create_stream_information(
+ SOUND_STREAM_TYPE_MEDIA, SoundStreamFocusCallback, this, &stream_info_);
+ if (SOUND_MANAGER_ERROR_NONE != err_sound) {
+ LoggerE("sound_manager_create_stream_information() failed: %d", err_sound);
+ stream_info_ = nullptr;
+ }
}
FMRadioManager::~FMRadioManager() {
@@ -349,6 +407,14 @@ FMRadioManager::~FMRadioManager() {
LoggerE("radio_destroy() failed: %d", err);
}
}
+
+ if (nullptr != stream_info_) {
+ const auto err = sound_manager_destroy_stream_information(stream_info_);
+ if (RADIO_ERROR_NONE != err) {
+ LoggerE("sound_manager_destroy_stream_information() failed: %d", err);
+ }
+ }
+
delete scan_data;
}
@@ -366,6 +432,7 @@ PlatformResult FMRadioManager::Start(double frequency) {
if (RADIO_STATE_READY != state && RADIO_STATE_PLAYING != state) {
return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Invalid radio state.");
}
+ LoggerD("Current radio state: %d", state);
PlatformResult result = SetFrequency(frequency);
@@ -373,11 +440,34 @@ PlatformResult FMRadioManager::Start(double frequency) {
return result;
}
- if (RADIO_STATE_READY == state) {
- return CheckError("radio_start", radio_start(radio_instance_));
- } else {
- return result;
+ if (RADIO_STATE_PLAYING == state) {
+ LoggerD("Radio is already started.");
+ return PlatformResult(ErrorCode::NO_ERROR);
+ }
+ // state == RADIO_STATE_READY
+ sound_stream_focus_state_e state_for_playback;
+ sound_stream_focus_state_e state_for_recording;
+
+ const auto err_focus_state =
+ sound_manager_get_focus_state(stream_info_, &state_for_playback, &state_for_recording);
+
+ if (SOUND_MANAGER_ERROR_NONE != err_focus_state) {
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Checking sound focus state failed.",
+ ("sound_manager_get_focus_state failed: %d", err_focus_state));
}
+
+ if (SOUND_STREAM_FOCUS_STATE_ACQUIRED != state_for_playback) {
+ LoggerD("Current sound stream focus state: %d, acquiring focus", state_for_playback);
+ const auto err_sound_focus = sound_manager_acquire_focus(
+ stream_info_, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, NULL);
+
+ if (SOUND_MANAGER_ERROR_NONE != err_sound_focus) {
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Acquiring sound focus failed.",
+ ("sound_manager_acquire_focus failed: %d", err_sound_focus));
+ }
+ }
+
+ return CheckError("radio_start", radio_start(radio_instance_));
}
PlatformResult FMRadioManager::Stop() {
@@ -395,7 +485,14 @@ PlatformResult FMRadioManager::Stop() {
return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Invalid radio state.");
}
- return CheckError("radio_stop", radio_stop(radio_instance_));
+ const auto err_radio_stop = radio_stop(radio_instance_);
+ const auto sound_focus_err = sound_manager_release_focus(
+ stream_info_, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, NULL);
+ if (SOUND_MANAGER_ERROR_NONE != sound_focus_err) {
+ LoggerE("sound_manager_release_focus() failed: %d", sound_focus_err);
+ }
+
+ return CheckError("radio_stop", err_radio_stop);
}
void FMRadioManager::SeekUp(double callback_id) {
@@ -495,15 +592,15 @@ void FMRadioManager::ScanStop(double callback_id) {
common::PlatformResult FMRadioManager::SetFMRadioInterruptedListener() {
ScopeLogger();
- const auto err = radio_set_interrupted_cb(radio_instance_, RadioInterruptedCallback, this);
- return CheckError("radio_set_interrupted_cb", err);
+ is_interrupted_listener_set = true;
+ return PlatformResult(ErrorCode::NO_ERROR);
}
common::PlatformResult FMRadioManager::UnsetFMRadioInterruptedListener() {
ScopeLogger();
- const auto err = radio_unset_interrupted_cb(radio_instance_);
- return CheckError("radio_unset_interrupted_cb", err);
+ is_interrupted_listener_set = false;
+ return PlatformResult(ErrorCode::NO_ERROR);
}
common::PlatformResult FMRadioManager::SetAntennaChangeListener() {
diff --git a/src/radio/radio_manager.h b/src/radio/radio_manager.h
index e32611d5..9484e6bb 100644
--- a/src/radio/radio_manager.h
+++ b/src/radio/radio_manager.h
@@ -24,6 +24,7 @@
#include <radio.h>
#include <runtime_info.h>
+#include <sound_manager.h>
#include "common/picojson.h"
#include "common/platform_result.h"
@@ -61,6 +62,9 @@ class FMRadioManager {
double GetSignalStrength();
bool HasAntenna();
const char* GetState();
+ bool IsInterruptedListenerSet();
+ radio_h GetRadioInstance();
+ sound_stream_info_h GetStreamInfo();
void PostMessage(const std::string& msg) const;
void PostResultSuccess(double callbackId, picojson::value* event) const;
@@ -71,6 +75,8 @@ class FMRadioManager {
RadioInstance& instance_;
radio_h radio_instance_;
RadioScanData* scan_data;
+ sound_stream_info_h stream_info_;
+ bool is_interrupted_listener_set;
};
struct RadioData {
diff --git a/src/secureelement/secureelement_instance.cc b/src/secureelement/secureelement_instance.cc
index eccb6925..75efd102 100644
--- a/src/secureelement/secureelement_instance.cc
+++ b/src/secureelement/secureelement_instance.cc
@@ -20,6 +20,7 @@
#include <thread>
#include "common/scope_exit.h"
+#include "common/task-queue.h"
#include "common/tools.h"
namespace extension {
@@ -186,7 +187,7 @@ TizenResult SecureElementInstance::GetReaders(picojson::object const& args,
this->Post(token, result);
};
- std::thread(get_readers, token).detach();
+ common::TaskQueue::GetInstance().Async(get_readers, token);
return TizenSuccess();
}
@@ -319,7 +320,7 @@ TizenResult SecureElementInstance::OpenSession(picojson::object const& args,
this->Post(token, result);
};
- std::thread(open_session, token).detach();
+ common::TaskQueue::GetInstance().Async(open_session, token);
return TizenSuccess();
}
@@ -396,7 +397,7 @@ TizenResult SecureElementInstance::OpenBasicChannel(picojson::object const& args
this->Post(token, result);
};
- std::thread(open_basic_channel, token).detach();
+ common::TaskQueue::GetInstance().Async(open_basic_channel, token);
return TizenSuccess();
}
@@ -441,7 +442,7 @@ TizenResult SecureElementInstance::OpenLogicalChannel(picojson::object const& ar
this->Post(token, result);
};
- std::thread(open_basic_logical, token).detach();
+ common::TaskQueue::GetInstance().Async(open_basic_logical, token);
return TizenSuccess();
}
@@ -582,7 +583,7 @@ TizenResult SecureElementInstance::Transmit(picojson::object const& args,
this->Post(token, result);
};
- std::thread(transmit, token).detach();
+ common::TaskQueue::GetInstance().Async(transmit, token);
return TizenSuccess();
}
diff --git a/src/sensor/sensor_api.js b/src/sensor/sensor_api.js
index 9305c4f1..f3380ef0 100755
--- a/src/sensor/sensor_api.js
+++ b/src/sensor/sensor_api.js
@@ -605,27 +605,28 @@ var GyroscopeRotationVectorSensor = function(data) {
GyroscopeRotationVectorSensor.prototype = new Sensor();
GyroscopeRotationVectorSensor.prototype.constructor = Sensor;
+
// prettier-ignore
GyroscopeRotationVectorSensor.prototype.getGyroscopeRotationVectorSensorData =
-function() {
- var args = validator_.validateArgs(arguments, [
- {
- name: 'successCallback',
- type: types_.FUNCTION
- },
- {
- name: 'errorCallback',
- type: types_.FUNCTION,
- optional: true,
- nullable: true
- }
- ]);
+ function() {
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION
+ },
+ {
+ name: 'errorCallback',
+ type: types_.FUNCTION,
+ optional: true,
+ nullable: true
+ }
+ ]);
- _sensorListeners[this.sensorType].getData(
- args.successCallback,
- errorWrapper.bind(args)
- );
-};
+ _sensorListeners[this.sensorType].getData(
+ args.successCallback,
+ errorWrapper.bind(args)
+ );
+ };
//// LinearAccelerationSensor
var LinearAccelerationSensor = function(data) {
@@ -743,7 +744,7 @@ AccelerationSensor.prototype.getAccelerationSensorData = function() {
);
};
-////////////////////// Sensor Data classes/////////////////////////////
+////////////////////// Sensor Data classes//////////////////////////
////Base SensorData class
var SensorData = function() {};
diff --git a/src/sensor/sensor_service.cc b/src/sensor/sensor_service.cc
index 1dcc339d..217ec36e 100644
--- a/src/sensor/sensor_service.cc
+++ b/src/sensor/sensor_service.cc
@@ -16,6 +16,7 @@
#include "sensor_service.h"
+#include <glib.h>
#include <memory>
#include <mutex>
#include <string>
diff --git a/src/sound/sound.gyp b/src/sound/sound.gyp
index e4210895..4466fb2d 100644
--- a/src/sound/sound.gyp
+++ b/src/sound/sound.gyp
@@ -27,8 +27,9 @@
[ 'tizen == 1', {
'variables': {
'packages': [
- 'vconf',
'capi-media-sound-manager',
+ 'vconf',
+ 'capi-base-common',
]
},
}],
diff --git a/src/sound/sound_api.js b/src/sound/sound_api.js
index f8dbabc8..7c3c86d2 100644
--- a/src/sound/sound_api.js
+++ b/src/sound/sound_api.js
@@ -78,15 +78,12 @@ ListenerManager.prototype.addListener = function(callback) {
};
ListenerManager.prototype.removeListener = function(watchId) {
- if (this.listeners.hasOwnProperty(watchId)) {
- delete this.listeners[watchId];
- } else {
- throw new WebAPIException(
- WebAPIException.INVALID_VALUES_ERR,
- 'Listener with id: ' + watchId + ' does not exist.'
- );
+ if (!this.listeners.hasOwnProperty(watchId)) {
+ return;
}
+ delete this.listeners[watchId];
+
if (this.nativeSet && type_.isEmptyObject(this.listeners)) {
this.native.callSync('SoundManager_removeDeviceStateChangeListener');
this.native.removeListener(this.listenerName);
@@ -140,9 +137,25 @@ SoundManager.prototype.getVolume = function(type) {
};
var _soundModeChangeListener;
+var _currentSoundMode;
+var _isFirstSoundModeChange = true;
+// Native side sometimes fires sound change callback two times in a row
+// with different values of sound mode. One of this value is only transitional
+// value caused by hazard of two values which should change simultaneously.
+// By waiting whether second callback would fire we bypass this problem.
function _soundModeChangeListenerCallback(result) {
- native_.callIfPossible(_soundModeChangeListener, native_.getResultObject(result));
+ _currentSoundMode = result;
+ if (_isFirstSoundModeChange) {
+ _isFirstSoundModeChange = false;
+ setTimeout(function() {
+ _isFirstSoundModeChange = true;
+ native_.callIfPossible(
+ _soundModeChangeListener,
+ native_.getResultObject(_currentSoundMode)
+ );
+ }, 100);
+ }
}
SoundManager.prototype.setSoundModeChangeListener = function(callback) {
diff --git a/src/sound/sound_instance.cc b/src/sound/sound_instance.cc
index 89e0b868..c45e7d67 100644
--- a/src/sound/sound_instance.cc
+++ b/src/sound/sound_instance.cc
@@ -132,6 +132,11 @@ void SoundInstance::SoundManagerUnsetSoundModeChangeListener(const picojson::val
void SoundInstance::OnSoundModeChange(const std::string& newmode) {
ScopeLogger();
+ if (current_sound_mode == newmode) {
+ LoggerD("New sound mode equals to current sound mode");
+ return;
+ }
+ current_sound_mode = newmode;
picojson::value event = picojson::value(picojson::object());
picojson::object& obj = event.get<picojson::object>();
picojson::value result = picojson::value(newmode);
diff --git a/src/sound/sound_instance.h b/src/sound/sound_instance.h
index 32a4c004..a800cf3b 100644
--- a/src/sound/sound_instance.h
+++ b/src/sound/sound_instance.h
@@ -45,6 +45,9 @@ class SoundInstance : public common::ParsedInstance, public SoundManagerSoundMod
void OnSoundModeChange(const std::string& newmode);
SoundManager manager_;
+
+ // It is used in OnSoundModeChange function to prevent double firing of callback
+ std::string current_sound_mode;
};
} // namespace sound
diff --git a/src/sound/sound_manager.cc b/src/sound/sound_manager.cc
index 8c98163d..fcbe1691 100644
--- a/src/sound/sound_manager.cc
+++ b/src/sound/sound_manager.cc
@@ -87,11 +87,12 @@ std::string SoundManager::SoundDeviceTypeToString(sound_device_type_e type) {
return "MIC";
case SOUND_DEVICE_AUDIO_JACK:
return "AUDIO_JACK";
- case SOUND_DEVICE_BLUETOOTH:
+ case SOUND_DEVICE_BLUETOOTH_MEDIA:
+ case SOUND_DEVICE_BLUETOOTH_VOICE:
return "BLUETOOTH";
case SOUND_DEVICE_HDMI:
return "HDMI";
- case SOUND_DEVICE_MIRRORING:
+ case SOUND_DEVICE_FORWARDING:
return "MIRRORING";
case SOUND_DEVICE_USB_AUDIO:
return "USB_AUDIO";
@@ -142,7 +143,7 @@ SoundManager::~SoundManager() {
}
if (SOUND_MANAGER_ERROR_NONE !=
- sound_manager_remove_device_state_changed_cb(sound_device_state_listener_id_)) {
+ sound_manager_remove_device_running_changed_cb(sound_device_state_listener_id_)) {
LoggerE("Cannot unregister state listener id == %d", sound_device_state_listener_id_);
}
}
@@ -197,7 +198,7 @@ double SoundManager::ConvertToSystemVolume(int max_volume, int volume) {
}
void SoundManager::VolumeChangeCallback(sound_type_e type, unsigned int value) {
- ScopeLogger("VolumeChangeCallback: type: %d, value: %d", type, value);
+ ScopeLogger("VolumeChangeCallback: type: %d, value: %u", type, value);
// Prepare response
picojson::value response = picojson::value(picojson::object());
@@ -506,14 +507,14 @@ PlatformResult SoundManager::GetDeviceInfo(sound_device_h device, bool is_connec
obj->insert(std::make_pair("direction", picojson::value(SoundIOTypeToString(direction))));
// get state
- sound_device_state_e state = SOUND_DEVICE_STATE_DEACTIVATED;
- ret = sound_manager_get_device_state(device, &state);
+ bool state = false;
+ ret = sound_manager_is_device_running(device, &state);
if (SOUND_MANAGER_ERROR_NONE != ret) {
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, "Getting device state failed",
- ("sound_manager_get_device_state error: %d (%s)", ret, get_error_message(ret)));
+ ("sound_manager_is_device_running error: %d (%s)", ret, get_error_message(ret)));
}
- obj->insert(std::make_pair("isActivated", picojson::value(static_cast<bool>(state))));
+ obj->insert(std::make_pair("isActivated", picojson::value(state)));
// get connection
if (check_connection) {
@@ -608,7 +609,7 @@ void DeviceConnectionChangedCB(sound_device_h device, bool is_connected, void* u
h->DeviceChangeCB(device, is_connected, false);
}
-void DeviceStateChangedCB(sound_device_h device, sound_device_state_e unused, void* user_data) {
+void DeviceStateChangedCB(sound_device_h device, bool unused, void* user_data) {
ScopeLogger();
SoundManager* h = static_cast<SoundManager*>(user_data);
@@ -630,13 +631,13 @@ PlatformResult SoundManager::AddDeviceStateChangeListener() {
ret, get_error_message(ret)));
}
- ret = sound_manager_add_device_state_changed_cb(mask, DeviceStateChangedCB, this,
- &sound_device_state_listener_id_);
+ ret = sound_manager_add_device_running_changed_cb(mask, DeviceStateChangedCB, this,
+ &sound_device_state_listener_id_);
if (SOUND_MANAGER_ERROR_NONE != ret) {
// silently cleanup connection changed callback registered in previous step
sound_manager_remove_device_connection_changed_cb(sound_device_connection_listener_id_);
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Setting state listener failed",
- ("sound_manager_add_device_state_changed_cb error: %d (%s)", ret,
+ ("sound_manager_add_device_running_changed_cb error: %d (%s)", ret,
get_error_message(ret)));
}
@@ -658,11 +659,11 @@ PlatformResult SoundManager::RemoveDeviceStateChangeListener() {
ret, get_error_message(ret)));
}
- ret = sound_manager_remove_device_state_changed_cb(sound_device_state_listener_id_);
+ ret = sound_manager_remove_device_running_changed_cb(sound_device_state_listener_id_);
if (SOUND_MANAGER_ERROR_NONE != ret) {
return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Removing state listener failed",
- ("sound_manager_remove_device_state_changed_cb error: %d (%s)", ret,
- get_error_message(ret)));
+ ("sound_manager_remove_device_running_changed_cb error: %d (%s)",
+ ret, get_error_message(ret)));
}
is_sound_device_change_listener_ = false;
diff --git a/src/systeminfo/systeminfo-utils.cpp b/src/systeminfo/systeminfo-utils.cpp
index 88822809..a7e9c43a 100644
--- a/src/systeminfo/systeminfo-utils.cpp
+++ b/src/systeminfo/systeminfo-utils.cpp
@@ -19,8 +19,8 @@
#include <memory>
-#include <device.h>
#include <net_connection.h>
+#include <runtime_info.h>
#include "common/logger.h"
#include "common/platform_exception.h"
@@ -121,17 +121,16 @@ PlatformResult SysteminfoUtils::CheckIfEthernetNetworkSupported() {
PlatformResult SysteminfoUtils::GetTotalMemory(long long *result) {
ScopeLogger();
- unsigned int value = 0;
-
- int ret = device_memory_get_total(&value);
- if (ret != DEVICE_ERROR_NONE) {
- std::string log_msg = "Failed to get total memory: " + std::to_string(ret);
+ runtime_memory_info_s info = {0};
+ int ret = runtime_info_get_system_memory_info(&info);
+ if (ret != RUNTIME_INFO_ERROR_NONE) {
+ std::string log_msg = "Failed to get system memory info: " + std::to_string(ret);
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, log_msg,
- ("device_memory_get_total error: %d (%s)", ret, get_error_message(ret)));
+ ("runtime_info_get_system_memory_info error: %d (%s)", ret, get_error_message(ret)));
}
- *result = static_cast<long long>(value) * MEMORY_TO_BYTE;
+ *result = static_cast<long long>(info.total) * MEMORY_TO_BYTE;
return PlatformResult(ErrorCode::NO_ERROR);
}
@@ -139,17 +138,19 @@ PlatformResult SysteminfoUtils::GetTotalMemory(long long *result) {
PlatformResult SysteminfoUtils::GetAvailableMemory(long long *result) {
ScopeLogger();
- unsigned int value = 0;
-
- int ret = device_memory_get_available(&value);
- if (ret != DEVICE_ERROR_NONE) {
- std::string log_msg = "Failed to get total memory: " + std::to_string(ret);
+ runtime_memory_info_s info = {0};
+ int ret = runtime_info_get_system_memory_info(&info);
+ if (ret != RUNTIME_INFO_ERROR_NONE) {
+ std::string log_msg = "Failed to get system memory info: " + std::to_string(ret);
return LogAndCreateResult(
ErrorCode::UNKNOWN_ERR, log_msg,
- ("device_memory_get_available error: %d (%s)", ret, get_error_message(ret)));
+ ("runtime_info_get_system_memory_info error: %d (%s)", ret, get_error_message(ret)));
}
- *result = static_cast<long long>(value) * MEMORY_TO_BYTE;
+ // as the WebIDL says the available memory means "amount of memory that is not in use (in bytes)",
+ // the result value is evaluated exactly this way, basing on total and used memory.
+ *result = static_cast<long long>(info.total - info.used) * MEMORY_TO_BYTE;
+
return PlatformResult(ErrorCode::NO_ERROR);
}
diff --git a/src/systeminfo/systeminfo.gyp b/src/systeminfo/systeminfo.gyp
index 5822c008..df47259f 100644
--- a/src/systeminfo/systeminfo.gyp
+++ b/src/systeminfo/systeminfo.gyp
@@ -33,17 +33,18 @@
['tizen == 1', {
'variables': {
'packages': [
- 'ecore',
- 'vconf',
- 'glib-2.0',
- 'capi-system-info',
- 'capi-network-connection',
- 'capi-system-device',
- 'capi-system-system-settings',
- 'capi-network-wifi-manager',
- 'libtzplatform-config',
- 'tapi',
- 'sensor',
+ 'capi-system-info',
+ 'capi-system-device',
+ 'vconf',
+ 'capi-network-connection',
+ 'capi-system-runtime-info',
+ 'tapi',
+ 'capi-network-wifi-manager',
+ 'capi-system-system-settings',
+ 'vconf-internal-keys',
+ 'sensor',
+ 'storage',
+ 'libtzplatform-config',
]
},
}],
diff --git a/src/systeminfo/systeminfo_api.js b/src/systeminfo/systeminfo_api.js
index 601f6618..d60c3afd 100644
--- a/src/systeminfo/systeminfo_api.js
+++ b/src/systeminfo/systeminfo_api.js
@@ -478,7 +478,7 @@ function SystemInfoStorageUnit(data) {
enumerable: true,
get: function() {
privUtils_.warn(
- 'DEPRECATION WARNING: SystemInfoStorageUnit.isRemoveable is ' +
+ 'DEPRECATION WARNING: SystemInfoStorageUnit.isRemoveable is is ' +
'deprecated and will be removed from next release. ' +
'Use SystemInfoStorageUnit.isRemovable instead.'
);
@@ -977,13 +977,13 @@ function _systeminfoBatteryListenerCallback(eventObj) {
* (T_.isUndefined(listener.lowThreshold) &&
* T_.isUndefined(listener.highThreshold)) ||
* (!T_.isUndefined(listener.lowThreshold) &&
- * !T_.isUndefined(listener.highThreshold) &&
- * (propObj.level <= listener.lowThreshold ||
- * propObj.level >= listener.highThreshold)) ||
+ * !T_.isUndefined(listener.highThreshold) &&
+ * (propObj.level <= listener.lowThreshold ||
+ * propObj.level >= listener.highThreshold)) ||
* (!T_.isUndefined(listener.lowThreshold) &&
- * (propObj.level <= listener.lowThreshold)) ||
+ * (propObj.level <= listener.lowThreshold)) ||
* (!T_.isUndefined(listener.highThreshold) &&
- * (propObj.level >= listener.highThreshold))
+ * (propObj.level >= listener.highThreshold))
*
* but it can be optimized like this:
*/
diff --git a/src/systeminfo/systeminfo_properties_manager.cc b/src/systeminfo/systeminfo_properties_manager.cc
index da705ebd..4b46b1b6 100644
--- a/src/systeminfo/systeminfo_properties_manager.cc
+++ b/src/systeminfo/systeminfo_properties_manager.cc
@@ -1208,7 +1208,7 @@ PlatformResult SysteminfoPropertiesManager::ReportStorage(picojson::object* out)
// handling storages from provider
common::FilesystemProvider& provider(common::FilesystemProvider::Create());
auto storages = provider.GetStorages();
- LoggerD("Storages found %d", storages.size());
+ LoggerD("Storages found %zu", storages.size());
for (auto storage : storages) {
if (storage->state() == common::StorageState::kMounted) {
unsigned long long available;
diff --git a/src/systeminfo/systeminfo_sim_details_manager.cc b/src/systeminfo/systeminfo_sim_details_manager.cc
index 3fb1c228..8b85d5b2 100644
--- a/src/systeminfo/systeminfo_sim_details_manager.cc
+++ b/src/systeminfo/systeminfo_sim_details_manager.cc
@@ -146,6 +146,8 @@ PlatformResult SimDetailsManager::GatherSimInformation(TapiHandle* handle, picoj
if (ret.IsError()) {
return ret;
}
+ // The variable used to determine if double mutex-locking is needed.
+ auto to_process_cached = to_process_;
{
// All props should be fetched synchronously, but sync function does not work
std::lock_guard<std::mutex> lock_to_process(sim_to_process_mutex_);
@@ -178,8 +180,16 @@ PlatformResult SimDetailsManager::GatherSimInformation(TapiHandle* handle, picoj
LoggerE("Failed getting iccid: %d", result);
}
}
- // prevent returning not filled result
- std::lock_guard<std::mutex> lock_sim(sim_info_mutex_);
+ // Here, the double mutex-locking may hang the application (thread) forever.
+ // This happens when none of above (4) getters succeeds (the to_process_ variable is not
+ // incremented).
+ // Usually, we would return and report an error, but the getPropertyValue and
+ // getPropertyValueArray methods do not invoke errorCallback with proper error type, thus silent
+ // error will be reported.
+ if (to_process_cached != to_process_) {
+ // Try to lock and wait for unlocking the sim_info_mutex_ by all registered callbacks.
+ std::lock_guard<std::mutex> lock_sim(sim_info_mutex_);
+ }
// result will come from callbacks
return PlatformResult(ErrorCode::NO_ERROR);
}
diff --git a/src/systemsetting/systemsetting.gyp b/src/systemsetting/systemsetting.gyp
index 815fed4f..96462fd7 100644
--- a/src/systemsetting/systemsetting.gyp
+++ b/src/systemsetting/systemsetting.gyp
@@ -21,7 +21,6 @@
'variables': {
'packages': [
'capi-system-system-settings',
- 'vconf',
]
},
}],
diff --git a/src/systemsetting/systemsetting_instance.cc b/src/systemsetting/systemsetting_instance.cc
index 8b28ba7c..55c58af5 100644
--- a/src/systemsetting/systemsetting_instance.cc
+++ b/src/systemsetting/systemsetting_instance.cc
@@ -21,6 +21,7 @@
#include "common/filesystem/filesystem_provider.h"
#include "common/logger.h"
#include "common/picojson.h"
+#include "common/scope_exit.h"
#include "common/task-queue.h"
#include "common/tools.h"
@@ -109,11 +110,15 @@ PlatformResult SystemSettingInstance::getPlatformPropertyValue(const std::string
// other values (not specified in the documentation) are handled in JS
switch (ret) {
- case SYSTEM_SETTINGS_ERROR_NONE:
+ case SYSTEM_SETTINGS_ERROR_NONE: {
+ SCOPE_EXIT {
+ free(value);
+ };
LoggerD("ret == SYSTEM_SETTINGS_ERROR_NONE");
+ CHECK_STORAGE_ACCESS_AND_RETURN(value);
result_obj.insert(std::make_pair("value", picojson::value(value ? value : "")));
- free(value);
return PlatformResult(ErrorCode::NO_ERROR);
+ }
case SYSTEM_SETTINGS_ERROR_NOT_SUPPORTED:
return LogAndCreateResult(
ErrorCode::NOT_SUPPORTED_ERR, "This property is not supported.",
@@ -137,10 +142,12 @@ void SystemSettingInstance::setProperty(const picojson::value& args, picojson::o
const std::string& value = args.get("value").get<std::string>();
LoggerD("Value to set: %s ", value.c_str());
- auto get = [this, type, value,
+ std::string real_path = common::FilesystemProvider::Create().GetRealPath(value);
+ CHECK_STORAGE_ACCESS(real_path, &out);
+
+ auto get = [this, type, real_path,
callback_id](const std::shared_ptr<picojson::value>& response) -> void {
ScopeLogger("Entered into asynchronous function, get");
- std::string real_path = common::FilesystemProvider::Create().GetRealPath(value);
PlatformResult status = setPlatformPropertyValue(type, real_path);
picojson::object& obj = response->get<picojson::object>();
if (status.IsSuccess()) {
@@ -154,7 +161,10 @@ void SystemSettingInstance::setProperty(const picojson::value& args, picojson::o
auto data = std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
- TaskQueue::GetInstance().Async<picojson::value>(get, data);
+ // Setting properties needs to be executed in main thread because of:
+ // "Internally, EFL uses data with TLSS(Thread Local Storage).
+ // Hence, there is no share data between Main thread and other thread."
+ TaskQueue::GetInstance().ScheduleWorkInMainThread<picojson::value>(get, data);
}
PlatformResult SystemSettingInstance::setPlatformPropertyValue(const std::string& settingType,
diff --git a/src/time/time_api.js b/src/time/time_api.js
index 3de42a61..9839b387 100644
--- a/src/time/time_api.js
+++ b/src/time/time_api.js
@@ -69,7 +69,7 @@ function _getTimezoneOffset(timestamp, tzName) {
}
function _getLocalTimezoneOffset(utcTimestamp) {
- // casting to milliseconds
+ // cast to milliseconds
return -1 * new Date(utcTimestamp).getTimezoneOffset() * 60 * 1000;
}
@@ -175,15 +175,15 @@ tizen.TZDate = function(p1, p2, day, hours, minutes, seconds, milliseconds, time
var offsetObject = _getTimezoneOffset(timezoneTimestamp, timezone);
offset = offsetObject.offset;
utcTimestamp = timezoneTimestamp - offset;
- // correction of missing/extra hour on DST change
+ //correction of missing/extra hour on DST change
var modifier = offsetObject.modifier;
if (modifier > 0) {
- // this is for case when 2AM becomes 3AM
- // (but offset must be corrected - missing one hour)
+ //this is for case when 2AM becomes 3AM (but offset must be
+ //corrected - missing one hour)
offset += modifier;
} else {
- // this is for case when extra hour appers - prevents error of
- // unnecessary shift of hour when timezone changes
+ //this is for case when extra hour appers - prevents error of
+ //unnecessary shift of hour when timezone changes
offset -= modifier;
utcTimestamp += modifier;
}
@@ -557,8 +557,8 @@ tizen.TZDate.prototype.toString = function() {
tizen.TZDate.prototype.getTimezoneAbbreviation = function() {
utils_.log('Entered TZDate.getTimezoneAbbreviation');
utils_.warn(
- 'DEPRECATION WARNING: getTimezoneAbbreviation() is deprecated ' +
- 'and will be removed from next release.'
+ 'DEPRECATION WARNING: getTimezoneAbbreviation() is deprecated and will be ' +
+ 'removed from next release.'
);
var result = native_.callSync('TZDate_getTimezoneAbbreviation', {
diff --git a/src/tizen/tizen_api.js b/src/tizen/tizen_api.js
index ee987071..5232c130 100644
--- a/src/tizen/tizen_api.js
+++ b/src/tizen/tizen_api.js
@@ -3,10 +3,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-/* eslint-disable */
+/*eslint-disable */
// Tizen API Specification:
-// https://developer.tizen.org/dev-guide/2.3.0/org.tizen.web.apireference/org.tizen.mobile.web.device.apireference/index.html
-/* eslint-enable */
+//https://developer.tizen.org/dev-guide/2.3.0/org.tizen.mobile.web.device.apireference/tizen/tizen.html
+/*eslint-enable */
// WebAPIException and WebAPIError definition moved to src/utils/utils_api.js
// for compliance reasons. You can find more info there.
diff --git a/src/tvinputdevice/tvinputdevice_api.js b/src/tvinputdevice/tvinputdevice_api.js
index 00576b18..3c5580f2 100755
--- a/src/tvinputdevice/tvinputdevice_api.js
+++ b/src/tvinputdevice/tvinputdevice_api.js
@@ -243,8 +243,8 @@ function TVInputDeviceKey(dict) {
}
/**
- * This class provides access to the API functionalities
- * through the tizen.tvinputdevice interface.
+ * This class provides access to the API functionalities through
+ * the tizen.tvinputdevice interface.
* @constructor
*/
function TVInputDeviceManager() {
@@ -299,8 +299,8 @@ TVInputDeviceManager.prototype.getKey = function(keyName) {
};
/**
- * Registers an input device key to receive DOM keyboard event
- * when it is pressed or released.
+ * Registers an input device key to receive DOM keyboard event when it is
+ * pressed or released.
* @param {!string} keyName The key name
*/
TVInputDeviceManager.prototype.registerKey = function(keyName) {
diff --git a/src/utils/utils_api.js b/src/utils/utils_api.js
index bad69c9f..1c5e9a9e 100644
--- a/src/utils/utils_api.js
+++ b/src/utils/utils_api.js
@@ -510,28 +510,27 @@ Converter.prototype.toString = function(val, nullable) {
};
function _toPlatformObject(val, types) {
- var v;
var t;
- if (_type.isArray(val)) {
- v = val;
- } else {
- v = [val];
- }
if (_type.isArray(types)) {
t = types;
} else {
t = [types];
}
+
+ if (_type.isArray(val)) {
+ throw new WebAPIException(
+ WebAPIException.TYPE_MISMATCH_ERR,
+ 'Cannot convert ' + String(val) + ' to ' + String(t[0].name) + '.'
+ );
+ }
+
var match = false;
for (var i = 0; i < t.length; ++i) {
- for (var j = 0; j < v.length; ++j) {
- match = match || v[j] instanceof t[i];
+ if (val instanceof t[i]) {
+ return val;
}
}
- if (match) {
- return val;
- }
throw new WebAPIException(
WebAPIException.TYPE_MISMATCH_ERR,
@@ -646,8 +645,8 @@ var Validator = function() {
* - values - required in case of some objects, value depends on type
* - validator - function which accepts a single parameter and returns true or false;
* if this property is present, this function will be executed,
- * argument converted to expected type is going to be passed to
- * this function
+ * argument converted to expected type is going to be passed to this
+ * function
*
* @param {Array} a - arguments of a method
* @param {Array} d - description of expected arguments
@@ -724,8 +723,8 @@ var Validator = function() {
* {
* name: 'first',
* type: Validator.Types.ARRAY,
- * values: Validator.Types.DOUBLE // converts elements,
- * only primitive types are supported
+ * values: Validator.Types.DOUBLE // converts elements, only primitive types are
+ * supported
* }
* ]
* @code
@@ -963,8 +962,8 @@ Validator.prototype.validateMethod = function(a, d) {
*/
Validator.prototype.isConstructorCall = function(obj, instance) {
if (!(obj instanceof instance) || obj._previouslyConstructed) {
- // There is no TypeError exception in Tizen 2.3.0 API spec
- // but it's required by current TCTs.
+ // There is no TypeError exception in Tizen 2.3.0 API spec but it's required by
+ // current TCTs.
// For Tizen compliance it's wrapped into WebAPIException.
throw new WebAPIException(
'TypeError',
@@ -1106,6 +1105,18 @@ var NativeManager = function(extension) {
try {
var msg = JSON_.parse(json);
} catch (error) {
+ // Because of special handling of power lock in chromium, the special
+ // signals:
+ // - __DisableChromiumInternalPowerLock
+ // - __EnableChromiumInternalPowerLock
+ // could occur. In such cases we are silently ignroing those messages.
+ // TODO This is workaround for missing patch in chromium-efl package
+ // which should handle this special message and don't forward it to
+ // webapi JS. After chromium-efl will be updated, below checking should
+ // be removed.
+ if (json.substring(0, 2) === '__') {
+ return;
+ }
xwalk.utils.error('Ignoring message - Invalid JSON received: ' + json);
return;
}
@@ -1256,8 +1267,8 @@ NativeManager.prototype.callIfPossible = function(callback) {
// WebAPIException and WebAPIError definition moved to Utils for compliance
// reasons with blink-wrt environment.
-// In blink-wrt the original Tizen module is loaded,
-// which is not providing exception constructor.
+// In blink-wrt the original Tizen module is loaded, which is not providing
+// exception constructor.
// As modules needs exceptions internally so they are loaded here for now.
// See http://168.219.209.56/gerrit/#/c/23472/ for more details.
// In future exception definition could be moved back to Tizen module.
@@ -1423,8 +1434,8 @@ var WebAPIException = function(code, message, name) {
});
this.constructor.prototype.__proto__ = Error.prototype;
- // V8-specific code
Error.captureStackTrace && Error.captureStackTrace(this, this.constructor);
+ // V8-specific code
};
WebAPIException.prototype.toString = function() {
diff --git a/src/utils/utils_extension.cc b/src/utils/utils_extension.cc
index 0b9d7a65..7cc85d3a 100644
--- a/src/utils/utils_extension.cc
+++ b/src/utils/utils_extension.cc
@@ -23,6 +23,7 @@ UtilsExtension::UtilsExtension() {
UtilsExtension::~UtilsExtension() {
ScopeLogger();
+ common::TaskQueue::GetInstance().Stop();
}
common::Instance* UtilsExtension::CreateInstance() {
diff --git a/src/utils/utils_instance.h b/src/utils/utils_instance.h
index c39a91d4..df065d52 100644
--- a/src/utils/utils_instance.h
+++ b/src/utils/utils_instance.h
@@ -7,6 +7,7 @@
#define UTILS_UTILS_INSTANCE_H_
#include "common/extension.h"
+#include "common/task-queue.h"
namespace extension {
namespace utils {
@@ -15,6 +16,9 @@ class UtilsInstance : public common::ParsedInstance {
public:
UtilsInstance();
virtual ~UtilsInstance() {
+ // At this point, frame of the page is destroyed or reloaded, so all the jobs have to be
+ // removed.
+ common::TaskQueue::GetInstance().DeleteJobs();
}
private:
diff --git a/src/widgetservice/widgetservice_api.js b/src/widgetservice/widgetservice_api.js
index 74b1f82e..00ba1d79 100644
--- a/src/widgetservice/widgetservice_api.js
+++ b/src/widgetservice/widgetservice_api.js
@@ -362,10 +362,6 @@ ListenerManager.prototype.addListener = function(callback) {
};
ListenerManager.prototype.removeListener = function(watchId) {
- if (this.listeners[watchId] === null || this.listeners[watchId] === undefined) {
- throw new WebAPIException(0, 'Watch id not found.', 'NotFoundError');
- }
-
if (this.listeners.hasOwnProperty(watchId)) {
delete this.listeners[watchId];
}
diff --git a/src/widgetservice/widgetservice_instance.cc b/src/widgetservice/widgetservice_instance.cc
index fd8f0baa..a6b6df2b 100644
--- a/src/widgetservice/widgetservice_instance.cc
+++ b/src/widgetservice/widgetservice_instance.cc
@@ -24,6 +24,7 @@
#include <widget_service.h>
#include "common/scope_exit.h"
+#include "common/task-queue.h"
#include "common/tools.h"
#include "widgetservice/widgetservice_utils.h"
@@ -257,7 +258,7 @@ TizenResult WidgetServiceInstance::GetWidgets(const picojson::object& args,
this->Post(token, result);
};
- std::thread(get_widgets, token).detach();
+ common::TaskQueue::GetInstance().Async(get_widgets, token);
return TizenSuccess();
}
@@ -361,7 +362,7 @@ TizenResult WidgetServiceInstance::GetInstances(picojson::object const& args,
this->Post(token, result);
};
- std::thread(get_instances, token).detach();
+ common::TaskQueue::GetInstance().Async(get_instances, token);
return TizenSuccess();
}
@@ -459,7 +460,7 @@ TizenResult WidgetServiceInstance::GetVariants(picojson::object const& args,
}
};
- std::thread(get_variants, token).detach();
+ common::TaskQueue::GetInstance().Async(get_variants, token);
return TizenSuccess();
}
@@ -586,7 +587,8 @@ TizenResult WidgetServiceInstance::SendContent(picojson::object const& args) {
LogAndReturnTizenError(common::AbortError(ret), ("bundle_add() failed"));
}
- int ret_widget = widget_service_trigger_update(widget_id.c_str(), instance_id.c_str(), data, force);
+ int ret_widget =
+ widget_service_trigger_update(widget_id.c_str(), instance_id.c_str(), data, force);
if (WIDGET_ERROR_NONE != ret_widget) {
LogAndReturnTizenError(WidgetServiceUtils::ConvertErrorCode(ret_widget),
("widget_service_trigger_update() failed"));
@@ -620,8 +622,8 @@ TizenResult WidgetServiceInstance::GetContent(picojson::object const& args,
bundle_free(bundle_data);
};
- int ret_widget = widget_service_get_content_of_widget_instance(widget_id.c_str(), instance_id.c_str(),
- &bundle_data);
+ int ret_widget = widget_service_get_content_of_widget_instance(
+ widget_id.c_str(), instance_id.c_str(), &bundle_data);
if (WIDGET_ERROR_NONE != ret_widget) {
LoggerE("widget_service_get_content_of_widget_instance() failed");
this->Post(token, WidgetServiceUtils::ConvertErrorCode(ret_widget));
@@ -642,7 +644,7 @@ TizenResult WidgetServiceInstance::GetContent(picojson::object const& args,
this->Post(token, TizenSuccess{response});
};
- std::thread(get_content, token).detach();
+ common::TaskQueue::GetInstance().Async(get_content, token);
return TizenSuccess();
}