Merge branch 'tizen_4.0' into tizen_5.0 98/244698/1
authorPiotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics <p.kosko@samsung.com>
Wed, 23 Sep 2020 08:26:55 +0000 (10:26 +0200)
committerPiotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics <p.kosko@samsung.com>
Wed, 23 Sep 2020 08:26:55 +0000 (10:26 +0200)
Change-Id: I2d5d3c4758a7181f8b66dce90a67485083866ed0

138 files changed:
packaging/webapi-plugins.spec
src/account/account.gyp
src/account/account_api.js
src/alarm/alarm.gyp
src/alarm/alarm_api.js
src/application/application_api.js
src/application/application_manager.cc
src/application/application_utils.cc
src/application/application_utils.h
src/archive/archive_api.js
src/archive/archive_file.cc
src/archive/archive_instance.cc
src/archive/filesystem_node.cc
src/archive/un_zip.cc
src/archive/un_zip_extract_request.cc
src/archive/zip_add_request.cc
src/badge/badge_manager.cc
src/bluetooth/bluetooth_api.js
src/calendar/calendar_item.cc
src/calendar/js/calendar.js
src/calendar/js/calendar_item.js
src/callhistory/callhistory.cc
src/common/GDBus/proxy.cpp
src/common/common.gyp
src/common/common.gypi
src/common/extension.cc
src/common/extension.h
src/common/logger.h
src/common/picojson.h
src/common/platform_enum.h [new file with mode: 0644]
src/common/task-queue.cpp
src/common/task-queue.h
src/common/tools.cc
src/common/tools.h
src/common/worker.cc [new file with mode: 0644]
src/common/worker.h [new file with mode: 0644]
src/contact/contact_instance.cc
src/contact/contact_util.cc
src/contact/js/contact.js
src/contact/js/person.js
src/content/content_instance.cc
src/content/content_manager.cc
src/content/content_manager.h
src/content/js/datatypes.js
src/content/js/manager.js
src/content/js/playlist.js
src/datacontrol/datacontrol_api.js
src/download/download_instance.cc
src/exif/exif_api.js
src/exif/exif_information.cc
src/exif/exif_instance.cc
src/exif/exif_tag_saver.cc
src/exif/get_exif_info.cc
src/exif/jpeg_file.cc
src/feedback/feedback_api.js
src/feedback/feedback_manager.cc
src/filesystem/filesystem_api.js
src/filesystem/filesystem_instance.cc
src/filesystem/filesystem_instance.h
src/filesystem/filesystem_manager.cc
src/filesystem/filesystem_manager.h
src/filesystem/filesystem_stat.cc
src/filesystem/filesystem_stat.h
src/filesystem/filesystem_utils.cc
src/filesystem/filesystem_utils.h
src/filesystem/js/common.js
src/filesystem/js/file.js
src/filesystem/js/file_handle.js [new file with mode: 0644]
src/filesystem/js/file_stream.js
src/filesystem/js/file_system_manager.js [changed mode: 0755->0644]
src/humanactivitymonitor/humanactivitymonitor_api.js
src/humanactivitymonitor/humanactivitymonitor_extension.cc
src/humanactivitymonitor/humanactivitymonitor_manager.cc
src/inputdevice/inputdevice_api.js
src/iotcon/iotcon_instance.cc
src/mediacontroller/mediacontroller_api.js
src/mediacontroller/mediacontroller_client.cc
src/mediacontroller/mediacontroller_client.h
src/mediacontroller/mediacontroller_instance.cc
src/mediacontroller/mediacontroller_server.cc
src/mediacontroller/mediacontroller_server.h
src/mediacontroller/mediacontroller_types.cc
src/mediacontroller/mediacontroller_types.h
src/messageport/messageport_api.js
src/messageport/messageport_instance.cc
src/messaging/DBus/MessageProxy.h
src/messaging/conversations_change_callback.cc
src/messaging/email_manager.cc
src/messaging/folders_change_callback.cc
src/messaging/message.cc
src/messaging/message.h
src/messaging/messages_change_callback.cc
src/messaging/messaging.gyp
src/messaging/messaging_api.js
src/messaging/messaging_instance.cc
src/messaging/messaging_util.cc
src/messaging/short_message_manager.cc
src/networkbearerselection/networkbearerselection_instance.cc
src/networkbearerselection/networkbearerselection_manager.cc
src/nfc/nfc_adapter.cc
src/nfc/nfc_api.js
src/nfc/nfc_util.cc
src/notification/common_notification.cc
src/package/package_api.js
src/package/package_instance.cc
src/package/package_instance.h
src/power/power_api.js
src/ppm/ppm_api.js
src/ppm/ppm_instance.cc
src/ppm/ppm_instance.h
src/preference/preference_manager.cc
src/push/push_api.js
src/radio/radio.gyp
src/radio/radio_manager.cc
src/radio/radio_manager.h
src/secureelement/secureelement_instance.cc
src/sensor/sensor_api.js
src/sensor/sensor_service.cc
src/sound/sound.gyp
src/sound/sound_api.js
src/sound/sound_instance.cc
src/sound/sound_instance.h
src/sound/sound_manager.cc
src/systeminfo/systeminfo-utils.cpp
src/systeminfo/systeminfo.gyp
src/systeminfo/systeminfo_api.js
src/systeminfo/systeminfo_properties_manager.cc
src/systeminfo/systeminfo_sim_details_manager.cc
src/systemsetting/systemsetting.gyp
src/systemsetting/systemsetting_instance.cc
src/time/time_api.js
src/tizen/tizen_api.js
src/tvinputdevice/tvinputdevice_api.js
src/utils/utils_api.js
src/utils/utils_extension.cc
src/utils/utils_instance.h
src/widgetservice/widgetservice_api.js
src/widgetservice/widgetservice_instance.cc

index 9d57052..5d426b6 100644 (file)
@@ -8,7 +8,7 @@
 %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions}
 
 Name:       webapi-plugins
-Version:    2.44
+Version:    2.51
 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" || ("%{?profile}" == "mobile" && "%{?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" || ("%{?profile}" == "mobile" && "%{?tizen_mobile_emulator_feature_callhistory_support}" == "1") || ("%{?profile}" == "wearable" && "%{?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" || ("%{?profile}" == "mobile" && "%{?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" || ("%{?profile}" == "mobile" && "%{?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" || ("%{?profile}" == "wearable" && "%{?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"
index 272a043..3fb0e3e 100644 (file)
@@ -22,7 +22,6 @@
         ['tizen == 1', {
           'variables': {
             'packages': [
-              'capi-appfw-package-manager',
               'accounts-svc',
             ]
           },
index 5c7c883..db4eb6f 100755 (executable)
@@ -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(
index 6a5739e..df129e0 100644 (file)
@@ -26,7 +26,9 @@
             'packages': [
               'capi-appfw-alarm',
               'capi-appfw-app-control',
+              'alarm-service',
               'capi-appfw-application',
+              'notification',
             ]
           },
         }],
index eb66886..98b4c7b 100755 (executable)
@@ -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.'
                     );
                 }
 
index 70586ee..8855b06 100755 (executable)
@@ -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);
                     }
index 69e2a55..74273f7 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "application_manager.h"
 
+#include <glib.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <type_traits>
@@ -521,28 +522,6 @@ void ApplicationManager::LaunchAppControl(const picojson::value& args) {
       }
     }
 
-    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>());
-        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;
-      }
-    }
-
     app_control_reply_cb callback = nullptr;
     struct ReplayCallbackData {
       ApplicationInstance* app_instance;
@@ -1368,8 +1347,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 +1381,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"));
index 596d292..27dfa61 100644 (file)
@@ -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,44 @@ 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 +430,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 +552,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();
index 455f197..308827b 100644 (file)
@@ -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);
 };
index cc1b585..61c2b99 100755 (executable)
@@ -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_fetchStorages', {});
+    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, [
index 7a9b795..e70923d 100644 (file)
@@ -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);
@@ -566,7 +566,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);
@@ -576,7 +576,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) {
index 7ee32b5..91a0afc 100644 (file)
@@ -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);
index 13d23f7..1d8048c 100644 (file)
@@ -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));
index 9689622..b381bdd 100644 (file)
@@ -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());
index 15b3370..841767a 100644 (file)
@@ -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);
 
index bbf823c..78840c6 100644 (file)
@@ -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);
index fab178e..b41f9cc 100644 (file)
@@ -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:
index 984fb77..1208798 100755 (executable)
@@ -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,
@@ -804,7 +804,7 @@ BluetoothLEDevice.prototype.removeConnectStateChangeListener = function() {
     _bleConnectChangeListener.removeListener(args.watchID);
 };
 
-// class BluetoothDevice //////////////////////
+// class BluetoothDevice //////////////////////////
 var BluetoothDevice = function(data) {
     var self = this;
     function _getter(field) {
@@ -914,7 +914,7 @@ BluetoothDevice.prototype.connectToServiceByUUID = function() {
     }
 };
 
-// class BluetoothServiceHandler //////////////////////
+// class BluetoothServiceHandler //////////////////////////
 function BluetoothServiceListeners() {
     var that = this;
     this.serviceCallback = function(data) {
@@ -1017,7 +1017,7 @@ BluetoothServiceHandler.prototype.unregister = function() {
     _bluetoothServiceListeners.removeListener(this.uuid);
 };
 
-// class BluetoothHealthApplication //////////////////////
+// class BluetoothHealthApplication //////////////////////////
 function BluetoothHealthApplicationListeners() {
     var that = this;
     this.appCallback = function(data) {
@@ -1111,7 +1111,7 @@ BluetoothHealthApplication.prototype.unregister = function() {
     _bluetoothHealthApplicationListeners.removeListener(this._id);
 };
 
-// class BluetoothProfileHandler //////////////////////
+// class BluetoothProfileHandler //////////////////////////
 var _BluetoothProfileType = {
     HEALTH: 'HEALTH'
 };
@@ -1124,7 +1124,7 @@ var BluetoothProfileHandler = function(data) {
     }
 };
 
-// class BluetoothHealthProfileHandler //////////////////////
+// class BluetoothHealthProfileHandler //////////////////////////
 var BluetoothHealthProfileHandler = function(data) {
     BluetoothProfileHandler.call(this, data);
 };
@@ -1234,7 +1234,7 @@ BluetoothHealthProfileHandler.prototype.connectToSource = function() {
     }
 };
 
-// class BluetoothHealthChannel //////////////////////
+// class BluetoothHealthChannel //////////////////////////
 var BluetoothHealthChannel = function(data) {
     Object.defineProperties(this, {
         peer: { value: data.peer, writable: false, enumerable: true },
@@ -1380,8 +1380,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);
  *
@@ -1485,7 +1485,7 @@ var _bleAdvertiseListener = _singleListenerBuilder(
     }
 );
 
-//class BluetoothLEAdapter //////////////////////
+//class BluetoothLEAdapter //////////////////////////
 var BluetoothLEAdapter = function() {};
 
 BluetoothLEAdapter.prototype.startScan = function() {
@@ -1599,7 +1599,7 @@ BluetoothLEAdapter.prototype.stopAdvertise = function() {
     }
 };
 
-//class BluetoothGATTService //////////////////////
+//class BluetoothGATTService //////////////////////////
 var BluetoothGATTService = function(data, address) {
     var handle_ = data.handle;
     var uuid_ = data.uuid;
@@ -1654,7 +1654,7 @@ var toByteArray = function(array) {
     return d;
 };
 
-//class BluetoothGATTCharacteristic //////////////////////
+//class BluetoothGATTCharacteristic //////////////////////////
 var BluetoothGATTCharacteristic = function(data, address) {
     var handle_ = data.handle;
     var descriptors_ = [];
@@ -1989,7 +1989,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
@@ -2072,7 +2072,7 @@ var BluetoothGATTDescriptor = function(data, address) {
     };
 };
 
-// class BluetoothAdapter //////////////////////
+// class BluetoothAdapter //////////////////////////
 var BluetoothAdapter = function() {
     function nameGetter() {
         var result = native.callSync('BluetoothAdapter_getName', {});
@@ -2180,9 +2180,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, [
@@ -2226,10 +2226,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, [
@@ -2699,7 +2698,7 @@ BluetoothAdapter.prototype.getBluetoothProfileHandler = function() {
     }
 };
 
-// class BluetoothManager //////////////////////
+// class BluetoothManager //////////////////////////
 var BluetoothManager = function() {
     Object.defineProperties(this, {
         deviceMajor: {
@@ -2749,5 +2748,5 @@ BluetoothManager.prototype.getLEAdapter = function() {
     privUtils_.log('Entered BluetoothManager.getLEAdapter()');
     return BluetoothManager_getLEAdapter();
 };
-// exports /////////////////////////////////////
+// exports /////////////////////////////////////////
 exports = new BluetoothManager();
index 99109bc..b3bc59d 100644 (file)
@@ -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");
index 6269df6..0aede5e 100755 (executable)
@@ -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)) {
index 38d1142..8f2ad6e 100644 (file)
@@ -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
         },
index 1108c80..9b61057 100644 (file)
@@ -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) {
index 86d4d6f..4b330fd 100644 (file)
@@ -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;
 }
index ff428ee..c3b685c 100644 (file)
         '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',
           ],
         },
       },
+      'defines': ['PICOJSON_USE_RVALUE_REFERENCE'],
     },
   ],
 }
index cf4fed8..4609a66 100644 (file)
@@ -82,6 +82,7 @@
       '-fvisibility=hidden',
       '-Wall',
       '-Werror',
+      '-Wformat-signedness',
     ],
     'cflags_c': [
       '-std=c11',
index 5347760..9fc1547 100644 (file)
@@ -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.");
     }
 
index 907d1df..9bb16f4 100644 (file)
@@ -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_;
index 3410dd8..228c871 100644 (file)
@@ -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);                                                                               \
   })
 #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_
index 44ae543..c6b9ade 100644 (file)
 /*
  * 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::stringkey) 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::strings, 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::stringpattern) {
+  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:
-  valueout_;
+  value *out_;
 
  public:
-  default_parse_context(valueout) : 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) {
-    arraya = 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) {
-    objecto = 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::strings) {
+inline void set_last_error(const std::string &s) {
   last_error_t<bool>::s = s;
 }
 
-inline const std::stringget_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 (file)
index 0000000..a7e22ca
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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 <initializer_list>
+#include <map>
+#include <string>
+#include <vector>
+
+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_
index 9bafdae..fe551a5 100644 (file)
@@ -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
index fb3300a..c44cc09 100644 (file)
 #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
index 17e8c4d..9901c66 100644 (file)
@@ -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();
 
index ee58b00..d958cf9 100644 (file)
@@ -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 (file)
index 0000000..4442c99
--- /dev/null
@@ -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 (file)
index 0000000..85aea8b
--- /dev/null
@@ -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
index 0b58bd8..939aaf0 100644 (file)
@@ -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
index eeefc42..f107843 100644 (file)
@@ -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,
index cf5098a..dcdd7de 100755 (executable)
@@ -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
index 16072c1..edcf84b 100755 (executable)
@@ -118,7 +118,7 @@ var Person = function(data) {
         },
         photoURI: {
             value: data.hasOwnProperty('photoURI') ? data.photoURI : null,
-            writable: true,
+            writable: false,
             enumerable: true
         },
         ringtoneURI: {
index 8a3de66..bc75361 100644 (file)
@@ -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);
index 9c069ed..86e2655 100644 (file)
@@ -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);
 }
 
index 1801ec4..af8efa7 100644 (file)
@@ -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);
index 1f8ec43..9ddfd0d 100755 (executable)
@@ -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;
         }
 
index 26f2964..3c58545 100755 (executable)
@@ -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 = {};
index 3b8ab05..14ff1fa 100755 (executable)
@@ -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
index 94bf83b..18ff77f 100755 (executable)
@@ -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;
 };
index f33102c..0ebd945 100644 (file)
@@ -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>();
index bd732e1..841ad21 100644 (file)
@@ -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;
-                    }
                 }
             }
         },
index 9a07286..6ed1bcc 100644 (file)
@@ -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) {
index 0687d70..28ae74c 100644 (file)
 #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>();
 
index 0d91766..74b8092 100644 (file)
@@ -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;
   }
 
index a5e4e81..4cd21c4 100644 (file)
@@ -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));
index 5fe598d..8c5e474 100644 (file)
@@ -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);
       }
index 8863c31..378d91c 100755 (executable)
@@ -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();
index 3aba534..07e0371 100644 (file)
@@ -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);
index cd2442c..38a9b26 100755 (executable)
@@ -18,4 +18,5 @@
 //= require('common.js');
 //= require('file_stream.js');
 //= require('file.js');
+//= require('file_handle.js');
 //= require('file_system_manager.js');
index aad8b44..1e93b7f 100644 (file)
 
 #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();
+
+  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 = fopen(path.c_str(), rewrite ? "w" : "r+");
+  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;
   }
+}
 
-  if (std::fflush(file)) {
-    throw std::runtime_error("error during file write");
+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;
+}
+
+/*
+ * 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
index 34c28ed..f3a6730 100644 (file)
 #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
index 1de8ae8..7e1ee1b 100644 (file)
@@ -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();
index ed237e6..d45aa12 100644 (file)
@@ -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);
 
index bb5bc89..feb7bed 100644 (file)
@@ -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;
index 31c5887..a984ab1 100755 (executable)
@@ -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
index c6d04e5..00b8c81 100644 (file)
  *    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())));
-}
 }
index f59048e..5888284 100644 (file)
 #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
index ff73801..1e4efbe 100644 (file)
@@ -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() {
@@ -243,9 +262,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)
@@ -395,11 +415,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) {
@@ -456,6 +472,7 @@ var commonFS_ = (function() {
         f_isSubDir: f_isSubDir,
         f_isCorrectRelativePath: f_isCorrectRelativePath,
         getStorage: getStorage,
-        getAllStorages: getAllStorages
+        getAllStorages: getAllStorages,
+        mergeMultipleSlashes: mergeMultipleSlashes
     };
 })();
index aa6fb1e..0848a8d 100644 (file)
@@ -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 (file)
index 0000000..47ab983
--- /dev/null
@@ -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);
+    }
+};
index abc389d..61add68 100644 (file)
@@ -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() {
old mode 100755 (executable)
new mode 100644 (file)
index 4de9373..943453f
@@ -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)) {
index 4f635f4..8397d1a 100755 (executable)
@@ -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();
index 6074271..e17fc87 100644 (file)
@@ -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() {
index e773809..1b2498a 100644 (file)
@@ -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";
@@ -1489,6 +1492,39 @@ 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;
+    PlatformResult result = SleepStateToString(state, &sleep_state);
+    if (!result) {
+      return result;
+    }
+
+    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");
 
@@ -1545,6 +1581,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)));
index d349d27..e828198 100644 (file)
@@ -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) {
index 6bc88a8..3eee147 100644 (file)
@@ -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);
index 7156bcc..f35f5be 100755 (executable)
@@ -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) {
index 429f141..c95fcb9 100644 (file)
@@ -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");
   }
@@ -64,6 +73,14 @@ 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);
 }
 
@@ -147,10 +164,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;
   }
 
@@ -181,7 +197,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;
@@ -189,7 +205,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;
@@ -235,7 +251,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(
@@ -244,10 +260,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;
   }
@@ -258,11 +274,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;
@@ -272,11 +288,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);
@@ -289,10 +305,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;
   }
 
@@ -314,9 +329,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) {
@@ -327,35 +342,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;
@@ -369,10 +384,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;
 
@@ -386,7 +401,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;
@@ -394,7 +409,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;
@@ -450,7 +465,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;
@@ -466,8 +481,7 @@ 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 {
@@ -475,13 +489,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(
@@ -489,12 +496,12 @@ 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;
@@ -502,67 +509,74 @@ 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;
+  /* TODO: Prepare an ACR and propose use case for request_id.
+  char* request_id = nullptr;
+  SCOPE_EXIT {
+    free(request_id);
+  };*/
   std::lock_guard<std::mutex> lock(handle_mutex_);
-  ret = mc_client_send_playback_state_command(handle_, server_name.c_str(),
-                                              static_cast<mc_playback_states_e>(state_e));
+  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);
index f1aa8c4..8ea1216 100644 (file)
@@ -47,8 +47,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();
@@ -72,8 +72,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);
index 350c4d6..1bf4a74 100644 (file)
@@ -19,6 +19,7 @@
 #include "common/logger.h"
 #include "common/picojson.h"
 #include "common/platform_result.h"
+#include "common/scope_exit.h"
 #include "common/task-queue.h"
 #include "common/tools.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,22 @@ 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 +336,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 +374,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 +407,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 +426,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 +449,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 +484,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 +520,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 +555,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 +590,34 @@ 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());
   };
 
-  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);
+  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"), 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 +627,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 +658,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 +673,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 +703,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;
   }
index 86204fb..d95e2fd 100644 (file)
@@ -75,27 +75,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) {
@@ -181,16 +179,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",
@@ -198,7 +194,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",
@@ -208,38 +204,30 @@ 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());
@@ -247,14 +235,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();
 
@@ -265,13 +253,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(
@@ -279,11 +260,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);
@@ -292,11 +273,11 @@ 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",
-                               ret, get_error_message(ret)));
+                              ("mc_server_set_custom_cmd_received_cb() error: %d, message: %s", ret,
+                               get_error_message(ret)));
   }
   command_listener_ = callback;
 
@@ -306,10 +287,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;
@@ -327,7 +308,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*/};
@@ -341,11 +322,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)));
   }
 
@@ -383,11 +366,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)));
   }
 
@@ -420,22 +403,31 @@ 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;
   }
 
@@ -443,7 +435,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);
 }
index 2fc1803..010f59b 100644 (file)
@@ -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
index f56c431..eb93147 100644 (file)
@@ -28,104 +28,66 @@ 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 +102,17 @@ 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 +130,29 @@ 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
index 20966aa..51de289 100644 (file)
 #include <map>
 #include <string>
 
+#include "common/platform_enum.h"
 #include "common/platform_result.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;
+namespace types {
 
-  static common::PlatformResult GetPlatformEnumMap(const std::string& type,
-                                                   std::map<std::string, int>* platform_str);
+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 StringToPlatformEnum(const std::string& type,
-                                                     const std::string& value, int* platform_enum);
+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 PlatformEnumToString(const std::string& type, int value,
-                                                     std::string* platform_str);
-
-  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);
-
- private:
-  static const PlatformEnumMap platform_enum_map_;
-  static PlatformEnumReverseMap platform_enum_reverse_map_;
-};
+}  // namespace types
 
 }  // namespace mediacontroller
 }  // namespace extension
index 031eb59..66d3524 100755 (executable)
  *    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++) {
@@ -42,69 +40,12 @@ extension.setMessageListener(function(json) {
             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
 }
@@ -121,22 +62,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;
 };
@@ -159,17 +100,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;
 };
@@ -188,13 +129,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(
@@ -220,13 +161,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(
@@ -250,6 +191,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] = [];
@@ -314,10 +257,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,
@@ -331,7 +274,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.'
@@ -339,7 +282,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)) {
@@ -351,7 +294,7 @@ RemoteMessagePort.prototype.sendMessage = function() {
                         );
                     }
                 }
-                filtered_data[i] = {
+                filteredData[i] = {
                     key: key,
                     value: value,
                     valueType: 'stringArrayValueType'
@@ -363,7 +306,7 @@ RemoteMessagePort.prototype.sendMessage = function() {
                         'Data is not octet array'
                     );
                 }
-                filtered_data[i] = {
+                filteredData[i] = {
                     key: key,
                     value: value,
                     valueType: 'byteStreamValueType'
@@ -377,7 +320,7 @@ RemoteMessagePort.prototype.sendMessage = function() {
                         );
                     }
                 }
-                filtered_data[i] = {
+                filteredData[i] = {
                     key: key,
                     value: value,
                     valueType: 'byteStreamArrayValueType'
@@ -385,26 +328,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();
index 9310888..3233e74 100644 (file)
@@ -175,7 +175,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);
@@ -296,29 +297,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,
@@ -344,30 +333,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)));
@@ -385,7 +362,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;
index 4089fcd..aeeb96b 100644 (file)
@@ -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>
index fe5f7e0..a53c8d3 100644 (file)
@@ -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);
index aeec4e2..5b89dd6 100644 (file)
 //#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()) {
index 6ceda0b..8bb67f2 100644 (file)
@@ -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);
index 80825fa..89d0a05 100644 (file)
@@ -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);
 }
index c4c5c15..7562fc3 100644 (file)
@@ -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);
index e0567dc..e0a48be 100644 (file)
@@ -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);
index 7edb5a6..620dbb7 100644 (file)
@@ -15,7 +15,6 @@
             'msg-service',
             'email-service',
             'dbus-1',
-            'dbus-glib-1',
             'capi-system-info',
             'ecore',
             'ecore-file',
index 53d4c61..d46536e 100755 (executable)
@@ -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, [
index 2cf41a5..9157866 100644 (file)
@@ -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()));
index 5884f0d..d7e6f32 100644 (file)
@@ -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());
index d1fc95c..069a686 100644 (file)
@@ -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();
index ea33972..a88cecc 100644 (file)
@@ -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);
 }
 
index b6206f4..33ec396 100644 (file)
@@ -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;
index f1725f3..65c87c4 100644 (file)
@@ -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) {
index 5eef7c2..851ee58 100644 (file)
@@ -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, [
index de51aaa..e91e1a1 100644 (file)
@@ -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);
 }
index 52cc10b..1f82493 100644 (file)
@@ -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);
 
index 9879bc5..fb89be0 100644 (file)
  *    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);
     }
 };
 
index d0a1147..a1ca888 100644 (file)
 
 #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);
 }
index 3ae7163..772d4cb 100644 (file)
@@ -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);
index 2c2a185..7a93b53 100755 (executable)
@@ -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', {});
index e6fa82a..972b581 100644 (file)
@@ -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();
index 7f419a3..039e430 100644 (file)
@@ -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
index 9d1825c..1df853d 100644 (file)
@@ -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
index ecd9665..95c82ee 100644 (file)
@@ -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();
 }
index 4e4e360..6bea2c9 100644 (file)
@@ -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)) {
index 79d37d5..6c09900 100644 (file)
         ['tizen == 1', {
           'variables': {
             'packages': [
+                'capi-system-runtime-info',
                 'vconf',
                 'capi-media-radio',
-                'capi-system-runtime-info',
+                'capi-media-sound-manager',
             ]
           },
         }],
index 2e9ea1e..9fe1b40 100644 (file)
@@ -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() {
index e32611d..9484e6b 100644 (file)
@@ -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 {
index eccb692..75efd10 100644 (file)
@@ -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();
 }
index 9305c4f..f3380ef 100755 (executable)
@@ -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() {};
 
index 1dcc339..217ec36 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "sensor_service.h"
 
+#include <glib.h>
 #include <memory>
 #include <mutex>
 #include <string>
index e421089..4466fb2 100644 (file)
@@ -27,8 +27,9 @@
         [ 'tizen == 1', {
             'variables': {
               'packages': [
-                'vconf',
                 'capi-media-sound-manager',
+                'vconf',
+                'capi-base-common',
               ]
             },
         }],
index f8dbabc..7c3c86d 100644 (file)
@@ -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) {
index 89e0b86..c45e7d6 100644 (file)
@@ -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);
index 32a4c00..a800cf3 100644 (file)
@@ -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
index 8c98163..fcbe169 100644 (file)
@@ -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;
index 4854376..88568f4 100644 (file)
@@ -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"
@@ -136,17 +136,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);
 }
@@ -154,17 +153,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);
 }
 
index 5822c00..df47259 100644 (file)
         ['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',
             ]
           },
         }],
index 601f661..d60c3af 100644 (file)
@@ -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:
              */
index da705eb..4b46b1b 100644 (file)
@@ -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;
index 3fb1c22..8b85d5b 100644 (file)
@@ -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);
   }
index 815fed4..96462fd 100644 (file)
@@ -21,7 +21,6 @@
           'variables': {
             'packages': [
               'capi-system-system-settings',
-              'vconf',
             ]
           },
         }],
index 8b28ba7..55c58af 100644 (file)
@@ -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,
index 3de42a6..9839b38 100644 (file)
@@ -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', {
index ee98707..5232c13 100644 (file)
@@ -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.
index 00576b1..3c5580f 100755 (executable)
@@ -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) {
index bad69c9..1c5e9a9 100644 (file)
@@ -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() {
index 0b9d7a6..7cc85d3 100644 (file)
@@ -23,6 +23,7 @@ UtilsExtension::UtilsExtension() {
 
 UtilsExtension::~UtilsExtension() {
   ScopeLogger();
+  common::TaskQueue::GetInstance().Stop();
 }
 
 common::Instance* UtilsExtension::CreateInstance() {
index c39a91d..df065d5 100644 (file)
@@ -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:
index 74b1f82..00ba1d7 100644 (file)
@@ -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];
     }
index bbd61c0..a6b6df2 100644 (file)
@@ -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();
 }
@@ -643,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();
 }