Merge branch 'tizen_3.0' into tizen_4.0 60/244460/1
authorPiotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics <p.kosko@samsung.com>
Fri, 18 Sep 2020 12:14:28 +0000 (14:14 +0200)
committerPiotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics <p.kosko@samsung.com>
Fri, 18 Sep 2020 12:14:28 +0000 (14:14 +0200)
Change-Id: I0abc0ed3a4c04aa1df20e4ef1b804cad4aed2088

171 files changed:
doc/README.md
doc/Tizen Avengers - WebApi Guidelines.pdf
doc/Type conversion table.xlsx [new file with mode: 0644]
doc/html/index.html
doc/package.json
doc/src/appendices.md [new file with mode: 0644]
doc/src/appendix_a.md [new file with mode: 0644]
doc/src/appendix_b.md [new file with mode: 0644]
doc/src/guideline.md
doc/src/implementation_cc.md
doc/src/implementation_js.md
doc/src/index.md
doc/src/plugin_structure.md
doc/src/tools.md
doc/src/widl.md
packaging/webapi-plugins.spec
src/alarm/alarm.gyp
src/alarm/alarm_api.js
src/alarm/alarm_instance.cc
src/alarm/alarm_manager.cc
src/alarm/alarm_manager.h
src/alarm/alarm_utils.cc
src/alarm/alarm_utils.h
src/application/application.gyp
src/application/application_api.js
src/application/application_instance.cc
src/application/application_instance.h
src/application/application_manager.cc
src/application/application_manager.h
src/archive/archive_callback_data.cc
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/bluetooth/bluetooth.gyp
src/bluetooth/bluetooth_health_profile_handler.cc
src/bluetooth/bluetooth_le_adapter.cc
src/bookmark/bookmark_extension.cc
src/calendar/calendar.cc
src/calendar/calendar_item.cc
src/calendar/calendar_manager.cc
src/common/GDBus/proxy.cpp
src/common/common.gyp
src/common/common.gypi
src/common/extension.cc
src/common/filesystem/filesystem_storage.cc
src/common/filter-utils.cc
src/common/logger.h
src/common/picojson.h
src/common/platform_result.cc
src/common/tools.cc
src/contact/addressbook.cc
src/contact/contact_search_engine.cc
src/contact/contact_util.cc
src/content/content_instance.cc
src/content/content_manager.cc
src/datacontrol/datacontrol_api.js
src/datacontrol/datacontrol_instance.cc
src/datacontrol/datacontrol_instance.h
src/download/download_api.js
src/download/download_instance.cc
src/download/download_instance.h
src/exif/exif_information.cc
src/exif/exif_information.h
src/exif/exif_tag_saver.cc
src/exif/exif_util.cc
src/exif/get_exif_info.cc
src/exif/jpeg_file.cc
src/exif/rational.cc
src/filesystem/filesystem_instance.cc
src/filesystem/filesystem_manager.cc
src/filesystem/filesystem_manager.h
src/filesystem/filesystem_stat.cc
src/filesystem/filesystem_stat.h
src/filesystem/js/file_stream.js
src/humanactivitymonitor/gesture_manager.cc [new file with mode: 0644]
src/humanactivitymonitor/gesture_manager.h [new file with mode: 0644]
src/humanactivitymonitor/humanactivitymonitor.gyp
src/humanactivitymonitor/humanactivitymonitor_api.js
src/humanactivitymonitor/humanactivitymonitor_instance.cc
src/humanactivitymonitor/humanactivitymonitor_instance.h
src/humanactivitymonitor/humanactivitymonitor_manager.cc
src/iotcon/iotcon_utils.cc
src/keymanager/keymanager_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/messaging/DBus/MessageProxy.cpp
src/messaging/MsgCommon/AbstractFilter.cpp
src/messaging/MsgCommon/AbstractFilter.h
src/messaging/MsgCommon/AttributeFilter.cpp
src/messaging/MsgCommon/AttributeFilter.h
src/messaging/MsgCommon/AttributeRangeFilter.cpp
src/messaging/MsgCommon/AttributeRangeFilter.h
src/messaging/MsgCommon/CompositeFilter.cpp
src/messaging/MsgCommon/CompositeFilter.h
src/messaging/change_listener_container.cc
src/messaging/email_manager.cc
src/messaging/message.cc
src/messaging/message_conversation.cc
src/messaging/message_service_email.cc
src/messaging/message_service_short_msg.cc
src/messaging/messages_change_callback.cc
src/messaging/messaging_database_manager.cc
src/messaging/messaging_database_manager.h
src/messaging/messaging_util.cc
src/messaging/messaging_util.h
src/messaging/short_message_manager.cc
src/nfc/nfc.gyp
src/nfc/nfc_adapter.cc
src/nfc/nfc_adapter.h
src/nfc/nfc_api.js
src/nfc/nfc_instance.cc
src/nfc/nfc_instance.h
src/nfc/nfc_message_utils.cc
src/nfc/nfc_util.cc
src/nfc/nfc_util.h
src/notification/common_notification.cc [new file with mode: 0644]
src/notification/common_notification.h [new file with mode: 0644]
src/notification/notification.gyp
src/notification/notification_api.js
src/notification/notification_extension.cc
src/notification/notification_instance.cc
src/notification/notification_instance.h
src/notification/notification_manager.cc
src/notification/notification_manager.h
src/notification/status_notification.cc
src/notification/status_notification.h
src/notification/user_notification.cc [new file with mode: 0644]
src/notification/user_notification.h [new file with mode: 0644]
src/power/power.gyp
src/power/power_manager.cc
src/ppm/ppm.gyp [new file with mode: 0644]
src/ppm/ppm_api.js [new file with mode: 0644]
src/ppm/ppm_extension.cc [new file with mode: 0644]
src/ppm/ppm_extension.h [new file with mode: 0644]
src/ppm/ppm_instance.cc [new file with mode: 0644]
src/ppm/ppm_instance.h [new file with mode: 0644]
src/preference/preference.gyp
src/push/push.gyp
src/radio/radio_manager.cc
src/sensor/sensor_api.js
src/sensor/sensor_service.cc
src/sound/sound_manager.cc
src/systeminfo/systeminfo.gyp
src/systeminfo/systeminfo_api.js
src/systeminfo/systeminfo_device_capability.cc
src/systeminfo/systeminfo_manager.cc
src/systeminfo/systeminfo_properties_manager.cc
src/time/time_manager.cc
src/tizen-wrt.gyp
src/utils/utils_api.js
src/utils/utils_instance.cc
src/utils/utils_instance.h
src/voicecontrol/voicecontrol.gyp [new file with mode: 0755]
src/voicecontrol/voicecontrol_api.js [new file with mode: 0755]
src/voicecontrol/voicecontrol_client.cc [new file with mode: 0644]
src/voicecontrol/voicecontrol_client.h [new file with mode: 0644]
src/voicecontrol/voicecontrol_extension.cc [new file with mode: 0644]
src/voicecontrol/voicecontrol_extension.h [new file with mode: 0644]
src/voicecontrol/voicecontrol_instance.cc [new file with mode: 0644]
src/voicecontrol/voicecontrol_instance.h [new file with mode: 0644]
src/voicecontrol/voicecontrol_util.cc [new file with mode: 0644]
src/voicecontrol/voicecontrol_util.h [new file with mode: 0644]
src/widgetservice/widgetservice_instance.cc

index 8c084bd..68c9b63 100644 (file)
@@ -4,7 +4,7 @@ HTML is generated from markdown files by:
 npm install # only once to install required packages
 npm run-script generate
 
-PDF is generated by "Print to PDF" in Chrome browser.
+PDF is generated by "Print to PDF" (CTRL+P) in Chrome browser.
 
 =====================================================
 Troubleshooting:
index ac6172f..83cce2c 100644 (file)
Binary files a/doc/Tizen Avengers - WebApi Guidelines.pdf and b/doc/Tizen Avengers - WebApi Guidelines.pdf differ
diff --git a/doc/Type conversion table.xlsx b/doc/Type conversion table.xlsx
new file mode 100644 (file)
index 0000000..e29e154
Binary files /dev/null and b/doc/Type conversion table.xlsx differ
index 1328643..7253e5a 100644 (file)
@@ -12,7 +12,7 @@
        <div class="separator"></div>
        <a title="Tizen Avengers - WebApi Guidelines" class="brand" href="#" style="background-image:url(images/tizen-logo_32h.png)"></a>
        <div class="separator"></div>
-       <ul id="sections"><li class="l2"><a href="#revision-history">Revision History</a></li><li class="l2"><a href="#overview">Overview</a></li><li class="l2"><a href="#guideline">Guideline</a><ul><li class="l3"><a href="#guideline/languages">Languages</a></li><li class="l3"><a href="#guideline/coding-style">Coding style</a></li><li class="l3"><a href="#guideline/api-guide">API guide</a></li><li class="l3"><a href="#guideline/unit-test-criteria">Unit test criteria</a></li><li class="l3"><a href="#guideline/source-code">Source code</a></li><li class="l3"><a href="#guideline/license-and-boilerplate">License and Boilerplate</a></li></ul></li><li class="l2"><a href="#plugin-structure">Plugin Structure</a><ul><li class="l3"><a href="#plugin-structure/conventions">Conventions</a></li><li class="l3"><a href="#plugin-structure/structure">Structure</a></li><li class="l3"><a href="#plugin-structure/spec-file">Spec file</a></li><li class="l3"><a href="#plugin-structure/manifest-file">Manifest file</a></li><li class="l3"><a href="#plugin-structure/gyp-file">GYP file</a></li><li class="l3"><a href="#plugin-structure/implementation-files">Implementation files</a></li><li class="l3"><a href="#plugin-structure/plugin-flow">Plugin flow</a></li></ul></li><li class="l2"><a href="#widl">WIDL</a><ul><li class="l3"><a href="#widl/conventions">Conventions</a></li><li class="l3"><a href="#widl/architecture">Architecture</a></li><li class="l3"><a href="#widl/example">Example</a></li></ul></li><li class="l2"><a href="#tools">Tools</a><ul><li class="l3"><a href="#tools/generate-stub-code">Generate stub code</a></li><li class="l3"><a href="#tools/using-multiple-javascript-files">Using multiple JavaScript files</a></li></ul></li><li class="l2"><a href="#implementation-javascript">Implementation - JavaScript</a><ul><li class="l3"><a href="#implementation-javascript/interface-creation">Interface creation</a></li><li class="l3"><a href="#implementation-javascript/creating-manager-entity">Creating Manager entity</a></li><li class="l3"><a href="#implementation-javascript/properties-definition">Properties definition</a></li><li class="l3"><a href="#implementation-javascript/methods-definition">Methods definition</a></li><li class="l3"><a href="#implementation-javascript/exporting-interface">Exporting interface</a></li><li class="l3"><a href="#implementation-javascript/utils">Utils</a></li><li class="l3"><a href="#implementation-javascript/exceptions">Exceptions</a></li><li class="l3"><a href="#implementation-javascript/synchronous-methods">Synchronous methods</a></li><li class="l3"><a href="#implementation-javascript/asynchronous-methods">Asynchronous methods</a></li><li class="l3"><a href="#implementation-javascript/listeners">Listeners</a></li></ul></li><li class="l2"><a href="#implementation-c">Implementation - C++</a><ul><li class="l3"><a href="#implementation-c/lifecycle-and-plugin-state">Lifecycle and plugin state</a></li><li class="l3"><a href="#implementation-c/privileges">Privileges</a></li><li class="l3"><a href="#implementation-c/namespace-and-entry-points">Namespace and entry points</a></li><li class="l3"><a href="#implementation-c/plugin-structure">Plugin structure</a></li><li class="l3"><a href="#implementation-c/asynchronous-calls">Asynchronous calls</a></li><li class="l3"><a href="#implementation-c/listeners">Listeners</a></li><li class="l3"><a href="#implementation-c/logger">Logger</a></li><li class="l3"><a href="#implementation-c/error-handling">Error handling</a></li></ul></li><li class="l2"><a href="#devel-package">Devel package</a><ul><li class="l3"><a href="#devel-package/package-structure">Package structure</a></li><li class="l3"><a href="#devel-package/creating-custom-web-device-plugins-module">Creating custom web device plugins module</a></li></ul></li></ul>
+       <ul id="sections"><li class="l2"><a href="#revision-history">Revision History</a></li><li class="l2"><a href="#overview">Overview</a></li><li class="l2"><a href="#guideline">Guideline</a><ul><li class="l3"><a href="#guideline/languages">Languages</a></li><li class="l3"><a href="#guideline/coding-style">Coding style</a></li><li class="l3"><a href="#guideline/api-guide">API guide</a></li><li class="l3"><a href="#guideline/unit-test-criteria">Unit test criteria</a></li><li class="l3"><a href="#guideline/source-code">Source code</a></li><li class="l3"><a href="#guideline/license-and-boilerplate">License and Boilerplate</a></li></ul></li><li class="l2"><a href="#plugin-structure">Plugin Structure</a><ul><li class="l3"><a href="#plugin-structure/conventions">Conventions</a></li><li class="l3"><a href="#plugin-structure/structure">Structure</a></li><li class="l3"><a href="#plugin-structure/spec-file">Spec file</a></li><li class="l3"><a href="#plugin-structure/manifest-file">Manifest file</a></li><li class="l3"><a href="#plugin-structure/gyp-file">GYP file</a></li><li class="l3"><a href="#plugin-structure/implementation-files">Implementation files</a></li><li class="l3"><a href="#plugin-structure/plugin-flow">Plugin flow</a></li><li class="l3"><a href="#plugin-structure/tizen-unified">Tizen Unified</a></li></ul></li><li class="l2"><a href="#widl">WIDL</a><ul><li class="l3"><a href="#widl/conventions">Conventions</a></li><li class="l3"><a href="#widl/architecture">Architecture</a></li><li class="l3"><a href="#widl/example-code-style">Example code style</a></li><li class="l3"><a href="#widl/example">Example</a></li></ul></li><li class="l2"><a href="#tools">Tools</a><ul><li class="l3"><a href="#tools/generate-stub-code">Generate stub code</a></li><li class="l3"><a href="#tools/using-multiple-javascript-files">Using multiple JavaScript files</a></li><li class="l3"><a href="#tools/format-code">Format code</a></li></ul></li><li class="l2"><a href="#implementation-javascript">Implementation - JavaScript</a><ul><li class="l3"><a href="#implementation-javascript/interface-creation">Interface creation</a></li><li class="l3"><a href="#implementation-javascript/creating-manager-entity">Creating Manager entity</a></li><li class="l3"><a href="#implementation-javascript/properties-definition">Properties definition</a></li><li class="l3"><a href="#implementation-javascript/methods-definition">Methods definition</a></li><li class="l3"><a href="#implementation-javascript/exporting-interface">Exporting interface</a></li><li class="l3"><a href="#implementation-javascript/utils">Utils</a></li><li class="l3"><a href="#implementation-javascript/exceptions">Exceptions</a></li><li class="l3"><a href="#implementation-javascript/synchronous-methods">Synchronous methods</a></li><li class="l3"><a href="#implementation-javascript/asynchronous-methods">Asynchronous methods</a></li><li class="l3"><a href="#implementation-javascript/listeners">Listeners</a></li></ul></li><li class="l2"><a href="#implementation-c">Implementation - C++</a><ul><li class="l3"><a href="#implementation-c/lifecycle-and-plugin-state">Lifecycle and plugin state</a></li><li class="l3"><a href="#implementation-c/privileges">Privileges</a></li><li class="l3"><a href="#implementation-c/namespace-and-entry-points">Namespace and entry points</a></li><li class="l3"><a href="#implementation-c/plugin-structure">Plugin structure</a></li><li class="l3"><a href="#implementation-c/dependencies-between-plugins">Dependencies between plugins</a></li><li class="l3"><a href="#implementation-c/asynchronous-calls">Asynchronous calls</a></li><li class="l3"><a href="#implementation-c/listeners">Listeners</a></li><li class="l3"><a href="#implementation-c/logger">Logger</a></li><li class="l3"><a href="#implementation-c/error-handling">Error handling</a></li></ul></li><li class="l2"><a href="#devel-package">Devel package</a><ul><li class="l3"><a href="#devel-package/package-structure">Package structure</a></li><li class="l3"><a href="#devel-package/creating-custom-web-device-plugins-module">Creating custom web device plugins module</a></li></ul></li><li class="l2"><a href="#appendices">Appendices</a><ul><li class="l3"><a href="#appendices/appendix-a-type-conversion-tables">Appendix A - type conversion tables</a></li><li class="l3"><a href="#appendices/appendix-b-javascript-code-example-style-guide">Appendix B - Javascript code example style guide</a></li></ul></li></ul>
        <div class="separator"></div>
        <div class="extra generated">
                Generated by <a href="https://github.com/DimitarChristoff/doctor" target="_blank" title="generate documentation from markdown">Doctor, MD</a>
 <td>0.1.0</td>
 <td>2015-05-15</td>
 <td>Initial Draft</td>
-<td>Wojciech Kosowicz<br><a href="mailto:w.kosowicz@samsung.com">&#119;&#x2e;&#107;&#x6f;&#x73;&#x6f;&#119;&#x69;&#x63;&#122;&#64;&#115;&#x61;&#x6d;&#115;&#117;&#110;&#103;&#46;&#99;&#x6f;&#109;</a></td>
+<td>Wojciech Kosowicz<br><a href="mailto:w.kosowicz@samsung.com">&#119;&#x2e;&#x6b;&#111;&#x73;&#111;&#119;&#105;&#99;&#x7a;&#64;&#115;&#x61;&#109;&#115;&#117;&#110;&#x67;&#x2e;&#99;&#x6f;&#x6d;</a></td>
 </tr>
 <tr>
 <td>0.2.0</td>
 <td>2015-05-22</td>
 <td>Extended version</td>
-<td>Pawel Kaczmarek<br><a href="mailto:p.kaczmarek3@samsung.com">&#112;&#x2e;&#107;&#x61;&#99;&#122;&#109;&#97;&#x72;&#101;&#x6b;&#51;&#64;&#115;&#97;&#x6d;&#115;&#x75;&#110;&#x67;&#46;&#x63;&#111;&#109;</a></td>
+<td>Pawel Kaczmarek<br><a href="mailto:p.kaczmarek3@samsung.com">&#x70;&#x2e;&#107;&#97;&#99;&#122;&#x6d;&#x61;&#x72;&#x65;&#107;&#x33;&#64;&#115;&#97;&#109;&#x73;&#117;&#x6e;&#x67;&#x2e;&#99;&#x6f;&#x6d;</a></td>
 </tr>
 <tr>
 <td>0.2.1</td>
 <td>2015-06-01</td>
 <td>Proofreading</td>
-<td>Rafal Galka<br><a href="mailto:r.galka@samsung.com">&#x72;&#x2e;&#x67;&#x61;&#108;&#107;&#97;&#x40;&#x73;&#97;&#x6d;&#x73;&#x75;&#110;&#103;&#x2e;&#99;&#111;&#109;</a></td>
+<td>Rafal Galka<br><a href="mailto:r.galka@samsung.com">&#x72;&#46;&#x67;&#x61;&#x6c;&#107;&#97;&#64;&#115;&#97;&#109;&#115;&#117;&#110;&#103;&#46;&#x63;&#111;&#109;</a></td>
 </tr>
 <tr>
 <td>0.3.0</td>
 <td>2015-06-08</td>
 <td>Supplemented C++ implementation guide</td>
-<td>Rafal Galka<br><a href="mailto:r.galka@samsung.com">&#114;&#x2e;&#103;&#97;&#108;&#107;&#97;&#x40;&#x73;&#97;&#109;&#x73;&#117;&#x6e;&#x67;&#x2e;&#x63;&#x6f;&#109;</a></td>
+<td>Rafal Galka<br><a href="mailto:r.galka@samsung.com">&#114;&#46;&#103;&#x61;&#108;&#x6b;&#97;&#64;&#x73;&#x61;&#x6d;&#x73;&#x75;&#110;&#x67;&#x2e;&#99;&#111;&#x6d;</a></td>
 </tr>
 <tr>
 <td>0.4.0</td>
 <td>2015-06-16</td>
 <td>Guideline</td>
-<td>Pawel Kaczmarek<br><a href="mailto:p.kaczmarek3@samsung.com">&#x70;&#46;&#x6b;&#97;&#99;&#122;&#x6d;&#x61;&#x72;&#x65;&#107;&#x33;&#x40;&#x73;&#x61;&#x6d;&#x73;&#x75;&#x6e;&#103;&#x2e;&#99;&#x6f;&#x6d;</a></td>
+<td>Pawel Kaczmarek<br><a href="mailto:p.kaczmarek3@samsung.com">&#x70;&#x2e;&#107;&#97;&#x63;&#122;&#x6d;&#97;&#x72;&#x65;&#107;&#51;&#64;&#x73;&#97;&#109;&#x73;&#x75;&#110;&#103;&#x2e;&#99;&#111;&#109;</a></td>
 </tr>
 <tr>
 <td>0.5.0</td>
 <td>2015-06-18</td>
 <td>Devel package</td>
-<td>Pawel Kaczmarek<br><a href="mailto:p.kaczmarek3@samsung.com">&#x70;&#46;&#107;&#97;&#99;&#x7a;&#109;&#97;&#114;&#101;&#107;&#x33;&#64;&#x73;&#97;&#x6d;&#115;&#x75;&#110;&#103;&#x2e;&#99;&#x6f;&#x6d;</a></td>
+<td>Pawel Kaczmarek<br><a href="mailto:p.kaczmarek3@samsung.com">&#x70;&#46;&#x6b;&#97;&#99;&#122;&#x6d;&#x61;&#114;&#101;&#107;&#51;&#64;&#x73;&#x61;&#109;&#115;&#117;&#110;&#103;&#x2e;&#99;&#111;&#109;</a></td>
 </tr>
 <tr>
 <td>0.5.1</td>
 <td>2015-06-24</td>
 <td>Add info about WAPIOven.py</td>
-<td>Pawel Kaczmarek<br><a href="mailto:p.kaczmarek3@samsung.com">&#112;&#46;&#107;&#97;&#99;&#x7a;&#x6d;&#x61;&#x72;&#x65;&#x6b;&#51;&#64;&#x73;&#97;&#x6d;&#115;&#x75;&#110;&#103;&#x2e;&#x63;&#111;&#x6d;</a></td>
+<td>Pawel Kaczmarek<br><a href="mailto:p.kaczmarek3@samsung.com">&#112;&#x2e;&#107;&#97;&#x63;&#122;&#109;&#97;&#x72;&#101;&#x6b;&#51;&#64;&#115;&#x61;&#109;&#x73;&#117;&#x6e;&#x67;&#x2e;&#99;&#x6f;&#x6d;</a></td>
 </tr>
 <tr>
 <td>0.6.0</td>
 <td>2016-10-28</td>
 <td>update devel package for tizen 3.0</td>
-<td>Annie Park<br><a href="mailto:hj.na.park@samsung.com">&#104;&#x6a;&#46;&#110;&#97;&#x2e;&#112;&#97;&#x72;&#107;&#64;&#115;&#x61;&#x6d;&#x73;&#x75;&#110;&#x67;&#x2e;&#99;&#x6f;&#x6d;</a></td>
+<td>Annie Park<br><a href="mailto:hj.na.park@samsung.com">&#x68;&#106;&#x2e;&#x6e;&#97;&#x2e;&#x70;&#97;&#x72;&#x6b;&#x40;&#115;&#x61;&#109;&#x73;&#117;&#110;&#103;&#x2e;&#99;&#111;&#x6d;</a></td>
+</tr>
+<tr>
+<td>0.7.0</td>
+<td>2017-11-09</td>
+<td>Update guidelines for Tizen 4.0</td>
+<td>Szymon Jastrzębski<br><a href="mailto:s.jastrzebsk@partner.samsung.com">&#x73;&#x2e;&#106;&#97;&#115;&#116;&#114;&#122;&#101;&#x62;&#x73;&#x6b;&#x40;&#112;&#97;&#114;&#116;&#x6e;&#101;&#x72;&#46;&#115;&#97;&#109;&#x73;&#117;&#x6e;&#103;&#x2e;&#x63;&#111;&#109;</a></td>
 </tr>
 </tbody>
 </table>
@@ -90,9 +96,12 @@ Each plugin should be written with great attention on JavaScript.</p>
 <h3 id="guideline/languages">Languages</h3>
 <p>C++, JavaScript</p>
 <h3 id="guideline/coding-style">Coding style</h3>
-<p>Use Google style guide,
-C++: <a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.html">http://google-styleguide.googlecode.com/svn/trunk/cppguide.html</a></p>
-<p>JavaScript: <a href="http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml">http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml</a></p>
+<p>Use Google style guides (with small exceptions):</p>
+<p>C++: <a href="https://google.github.io/styleguide/cppguide.html">https://google.github.io/styleguide/cppguide.html</a></p>
+<p>JavaScript: <a href="https://google.github.io/styleguide/jsguide.html">https://google.github.io/styleguide/jsguide.html</a></p>
+<p>On branches <code>tizen_3.0</code> and higher, the C++ <del>and JavaScript</del> files are formatted using scripts,
+which its usage is described in the <a href="#tools/format-code">Format code</a> section of this document.
+The section also describes where the exceptions from Google coding style are defined.</p>
 <h3 id="guideline/api-guide">API guide</h3>
 <p>Tizen Web Device API Guide Lines.pptx
 <a href="http://platform.sec.samsung.net/slp/Tizen/Tizen%20Managed%20API/Web%20Device%20API/Tizen%20Web%20Device%20API%20Guide%20Lines.pptx">http://platform.sec.samsung.net/slp/Tizen/Tizen%20Managed%20API/Web%20Device%20API/Tizen%20Web%20Device%20API%20Guide%20Lines.pptx</a></p>
@@ -105,15 +114,15 @@ C++: <a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.html">h
 $ cd webapi-plugins
 $ git checkout origin/tizen_2.4
 </code></pre>
-<p>For Tizen 3.0</p>
-<pre><code class="lang-sh">$ git clone ssh://&lt;user.id&gt;@168.219.209.56:29418/framework/web/webapi-plugins
+<p>For Tizen 3.0 and higher</p>
+<pre><code class="lang-sh">$ git clone ssh://&lt;user.id&gt;@review.tizen.org:29418/platform/core/api/webapi-plugins &amp;&amp; scp -p -P 29418 &lt;user.id&gt;@review.tizen.org:hooks/commit-msg webapi-plugins/.git/hooks/
 $ cd webapi-plugins
-$ git checkout origin/tizen_3.0
+$ git checkout origin/tizen_&lt;tizen_version&gt;
 </code></pre>
 <h3 id="guideline/license-and-boilerplate">License and Boilerplate</h3>
 <p>Use this boilerplate in every new created source files.</p>
 <pre><code class="lang-sh">/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) &lt;year of file creation&gt; Samsung Electronics Co., Ltd All Rights Reserved
  *
  *    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
  *    you may not use this file except in compliance with the License.
@@ -141,13 +150,25 @@ $ git checkout origin/tizen_3.0
 <li><code>&lt;pluginname&gt;_instance.h</code></li>
 <li><code>&lt;pluginname&gt;_instance.cc</code></li>
 </ul>
+<p>Additionally, plugins may contain below structure, depending on the WIDL specification file:</p>
+<ul>
+<li><code>&lt;pluginname&gt;_client.h</code></li>
+<li><code>&lt;pluginname&gt;_client.cc</code></li>
+<li><code>&lt;pluginname&gt;_server.h</code></li>
+<li><code>&lt;pluginname&gt;_server.cc</code></li>
+<li><code>&lt;pluginname&gt;_service.h</code></li>
+<li><code>&lt;pluginname&gt;_service.cc</code></li>
+<li><code>&lt;pluginname&gt;_util.h</code></li>
+<li><code>&lt;pluginname&gt;_util.cc</code></li>
+</ul>
+<p>and other files with similar naming-convention needed by the developer.</p>
 <h3 id="plugin-structure/spec-file">Spec file</h3>
 <p>Spec file (<code>webapi-plugins.spec</code>) kept inside <code>packaging/</code> directory
-is build specification file used by RPM packaging system where variables are defined.
+is build specification file used by RPM packaging system where variables are defined.
 Those variables can be used to include or exclude particular modules from
 build for each profile (mobile, TV, wearable).</p>
 <h3 id="plugin-structure/manifest-file">Manifest file</h3>
-<p>Each RPM package must have a manifest file where developers can specify the access control domain
+<p>Each RPM package must have a manifest file, where developers can specify the access control domain
 in which their application should be running and potentially additional security policies for the
 application. It is necessary to build the project. The manifest file (<code>webapi-plugins.manifest</code>)
 is located in the root directory of the project.</p>
@@ -168,7 +189,7 @@ These files are responsible for communication between JavaScript layer and Nativ
 This file contains all methods required by each API.
 All operation should be done by JavaScript as much as possible.
 If JavaScript can do something, it should do it.
-This file is responsible for checking arguments, calling C++ methods etc.</li>
+This file is responsible for checking and validating arguments, calling C++ methods etc.</li>
 </ul>
 <h3 id="plugin-structure/plugin-flow">Plugin flow</h3>
 <p><img src="images/plugin_flow.png" alt="Plugin flow"></p>
@@ -178,11 +199,26 @@ This file is responsible for checking arguments, calling C++ methods etc.</li>
 This information consists of type of call (asynchronous, synchronous)
 arguments given by user, any additional information that is required to
 successfully acquire required data. Data is sent in form of JSON.</li>
-<li>C++ parses acquired JSON. After the data is processed. Appropriate platform
+<li>C++ parses acquired JSON. After the data is processed, appropriate platform
 functions are called with the specified arguments.</li>
 <li>Platform returns specified values to C++ layer.</li>
-<li>Another JSON is formed. It consists of data that was acquired from platform.</li>
+<li>Another JSON is formed. It consists of data that was acquired from platform.
+The data is sent to JavaScript layer.</li>
 </ol>
+<h3 id="plugin-structure/tizen-unified">Tizen Unified</h3>
+<p>With Tizen 4.0 an idea of Tizen Unified was introduced.</p>
+<p>Before Tizen 4.0, each profile specified in <code>.gbs.conf</code> file defined the package repositories
+for a single device type and a particular architecture.</p>
+<p>Since Tizen 4.0, each GBS profile is associated with a particular architecture and all device types.</p>
+<p>Each device with given profile and architecture requires to have at least 2 RPM files installed:</p>
+<pre><code class="lang-sh">webapi-plugins-x.y-z.ARCH.rpm
+webapi-plugins-profile_PROFILE_NAME-x.y-z.ARCH.rpm
+</code></pre>
+<p>However, emulators require to have 3 RPM files installed:</p>
+<pre><code class="lang-sh">webapi-plugins-x.y-z.i686.rpm
+webapi-plugins-profile_PROFILE_NAME-x.y-z.i686.rpm
+webapi-plugins-PROFILE_NAME-extension-emulator-x.y-z.i686.rpm
+</code></pre>
 <h2 id="widl">WIDL</h2>
 <h3 id="widl/conventions">Conventions</h3>
 <p>Currently WIDL version that is used in Samsung is described here: <a href="http://www.w3.org/TR/WebIDL/">http://www.w3.org/TR/WebIDL/</a>.
@@ -212,7 +248,7 @@ In interface definition you can put following members:</p>
 can be changed, if it is not read only.</li>
 <li>Operation: Interface member, which represents method inside object.
 It is a function of programming language, which can be executed and returns a result.</li>
-<li>Special operation: Performs a specific task. i.e. deleter, getter</li>
+<li>Special operation: Performs a specific task. i.e. deleter, getter.</li>
 <li>Static operation: It is not called for a specific instance of the interface,
 is called for static object regardless of an instance creation.
 It is connected with the interface itself.</li>
@@ -238,8 +274,8 @@ It is connected with the interface itself.</li>
 <pre class="prettyprint linenums"><code>Tizen implements ManagerObject
 </code></pre><p>To provide actual implementations of ManagerObject, instance of its Manager
 interface definition has to be made. Inside this Manager interface all attributes
-and functions that will be available form manager namespace, should be defined.
-There can be attributes which are other interfaces, operations and everything
+and functions that will be available from manager namespace, should be defined.
+There can be attributes, which are other interfaces, operations and everything
 that interfaces allows.</p>
 <p>Additional interface can be available as a standalone types not connected to
 global namespace. Those are either obtained from operation of other interfaces
@@ -270,7 +306,10 @@ lacks of keyword <code>FunctionOnly</code>.</p>
   void secondmethod(type somearg2, ... );
   any additional methods...
 };
-</code></pre><h3 id="widl/example">Example</h3>
+</code></pre><h3 id="widl/example-code-style">Example code style</h3>
+<p>Coding style for example codes put in the between <code>\code</code>  and <code>\endcode</code> tags
+should be written with respect to rules described in <a href="#appendices/appendix-b-javascript-code-example-style-guide">the Appendix B</a>.</p>
+<h3 id="widl/example">Example</h3>
 <p>Example of WIDL file:</p>
 <pre class="prettyprint linenums"><code>module Sample {
 
@@ -301,6 +340,7 @@ lacks of keyword <code>FunctionOnly</code>.</p>
 };
 </code></pre><h2 id="tools">Tools</h2>
 <h3 id="tools/generate-stub-code">Generate stub code</h3>
+<h4 id="-span-style-color-red-the-generator-is-no-longer-maintained-span-"><span style="color:red"><strong>The generator is no longer maintained.</strong></span></h4>
 <p>To generate stub files from the widl you can use stub generator located in
 <code>tools/skeleton_generator/</code> directory and run the python command:</p>
 <pre><code class="lang-sh">$ python WAPIOven.py -d &lt;stub code destination directory name&gt; &lt;widl directory/pluginname&gt;.widl
@@ -321,7 +361,7 @@ $ python WAPIOven.py -d ../../src/notification/ /web-device-api/web/widl/tizen/n
 <p>WIDL files can be found in the project repository:</p>
 <pre><code class="lang-sh">$ git clone ssh://&lt;username&gt;@168.219.209.56:29418/doc/web-device-api
 </code></pre>
-<p>The widl files are placed in: <code>web-device-api/web/widl/tizen/</code></p>
+<p>The widl files are placed in: <code>web-device-api/web/widl/tizen/</code> directory.</p>
 <p>Stub files generated by above command:</p>
 <pre><code class="lang-sh">&lt;pluginname&gt;_api.js
 &lt;pluginname&gt;_extension.h
@@ -350,11 +390,33 @@ plugin directory and place JavaScript files.</p>
 <p>To merge all JavaScript files <code>tools/mergejs.py</code> file is used.
 This script merge all files mentioned in <code>&lt;pluginname&gt;_api.js</code> file into one
 file before build process.</p>
+<h3 id="tools/format-code">Format code</h3>
+<p>To format code use scripts provided in the <code>tools/codestyle</code> directory.</p>
+<p><code>cpplint</code> is used to validate C++ and <code>eslint</code> for JavaScript files.</p>
+<p><strong>Currently, the JavaScript validator and formatter seems to be a little buggy,
+thus it is not recommended to use.</strong></p>
+<p>The developer needs to have <code>python</code>, <code>node.js</code>, <code>eslint</code>, <code>Closure Linter</code> and <code>clang-format</code> installed.</p>
+<p>It is worth to make life easier by creating symbolic link to <code>clang-format</code>.</p>
+<pre><code class="lang-sh">sudo ln -s /usr/bin/clang-format-&lt;clang format version&gt; /usr/bin/clang-format
+</code></pre>
+<p>For convenience, in the root of the project links were provided for easier access:</p>
+<ul>
+<li><code>code_format -&gt; tools/codestyle/code_formatter.sh</code></li>
+<li><code>code_validate -&gt; tools/codestyle/code_validation.sh</code></li>
+</ul>
+<p>Those scripts consist of configuration for rules regarding the Google style guides, with few exceptions.</p>
+<p>To format and validate C++ and JavaScript code run in the root of the project:</p>
+<pre><code class="lang-sh">./code_validate -a # -a for all, -c for C++, -js for JavaScript files
+./code_format -a   # use -h or --help for help
+</code></pre>
+<p>The scripts also accept a path to module&#39;s directory.
+By default every directory module in the <code>src</code> directory is used.</p>
+<p>For more details, please see <code>tools/codestyle/README</code> file.</p>
+<p>This rule concerns to branches <code>tizen_3.0</code> and above.</p>
 <h2 id="implementation-javascript">Implementation - JavaScript</h2>
 <p>Each plugin contains JavaScript files. This is the place where user input is
-being processed validated before send to C++ layer.</p>
-<p>Badge API will be used to show the creation of JavaScript file (lot of content
-of this file will be already generated via Stub Generator).</p>
+being processed validated before sending to C++ layer.</p>
+<p>Badge API will be used to show the creation of JavaScript file.</p>
 <h3 id="implementation-javascript/interface-creation">Interface creation</h3>
 <p>The WIDL of BadgeManager – main entity that holds all the API methods
 looks like following:</p>
@@ -406,12 +468,12 @@ var number = converter_.toLong(result);
 </code></pre>
 <h4 id="validator">Validator</h4>
 <p>When API JavaScript method is called first thing that has to be done in
-JavaScript layer of api implementation is to process and validate arguments
+JavaScript layer of API implementation is to process and validate arguments
 given by the user. The process of validation consists of ensuring that the
 proper amount of arguments was given and that they were of the expected
 type and throwing exception if necessary.</p>
 <p>Validator helps to ensure that user sent proper values. Validator is available
-at <code>xwalk.utils.validator</code> and predefined js types at <code>xwalk.utils.validator.types</code></p>
+at <code>xwalk.utils.validator</code> and predefined JavaScript types at <code>xwalk.utils.validator.types</code></p>
 <p>Below can be found example of using validator inside <code>setBadgeCount</code> method
 that requires appId in form of string and long count value:</p>
 <pre class="prettyprint linenums"><code class="lang-js">var validator_ = xwalk.utils.validator;
@@ -422,6 +484,9 @@ var args = validator_.validateArgs(arguments, [
   {name: &#39;count&#39;, type: types_.LONG}
 ]);
 </code></pre>
+<p>The <code>validateArgs</code> method may also validate optional and nullable arguments.
+See its definition in file <code>src/utils/utils_api.js</code>.</p>
+<p>This method respecting the JavaScript type conversion rules is presented <a href="#appendices/appendix-a-type-conversion-tables">the Appendix A - type conversion tables</a>.</p>
 <h3 id="implementation-javascript/exceptions">Exceptions</h3>
 <p>At some point whether improper data is received or given to JavaScript might
 require to throw exceptions. The example below shows how to throw properly
@@ -431,6 +496,8 @@ predefined exceptions:</p>
 </code></pre>
 <p>WebAPIException constructor takes as argument the type of error to be thrown.
 The second additional argument is error message.</p>
+<p>There might be a need to throw expception because of failure received from C++ layer,
+for this case see below section.</p>
 <h3 id="implementation-javascript/synchronous-methods">Synchronous methods</h3>
 <p>In order to perform synchronous operation (one that does not require callback
 and the result is given instantly) callSync() method of Native manager needs
@@ -450,9 +517,9 @@ Result is assigned to ret variable.</p>
 <h3 id="implementation-javascript/asynchronous-methods">Asynchronous methods</h3>
 <p>In order to work with method that requires callback instead of callSync(),
 call() method needs to be called. Apart from the first two arguments that are
-exactly the same as in call() method (c++ method binding, object) it takes
+exactly the same as in callSync() method (C++ method binding, object) it takes
 additional argument that is a function that will be called when the native
-call is processed:</p>
+call response is processed:</p>
 <pre class="prettyprint linenums"><code class="lang-js">var native_ = new xwalk.utils.NativeManager(extension);
 var callback = function(result) {
   if (native_.isFailure(result)) {
@@ -500,6 +567,13 @@ no strict reference between JavaScript and native data.<br>
 Example: If operation should change some object retrieved from platform,
 identifier should be passed again and additional check if object still exists
 should be made.</p>
+<p>According to <a href="https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables">Google C++ Style Guide</a> static variables should <strong>NOT</strong> be used.</p>
+<p>This rule concerns especially to <code>&lt;pluginname&gt;Manager</code>, <code>&lt;pluginname&gt;Client</code>,
+<code>&lt;pluginname&gt;Server</code> etc. classes, which tend to implement the Singleton design pattern.
+Because of this, the above mentioned classes&#39; instances should <strong>NOT</strong> be declared as <code>static</code>
+and should <strong>NOT</strong> be got through <code>getInstance</code> methods.
+Instead, the classes&#39;s instances should be declared as an <code>private</code> attribute of
+<code>&lt;pluginname&gt;Instance</code> class.</p>
 <h3 id="implementation-c/privileges">Privileges</h3>
 <p>Some of the API methods require privilege access. The privilege engine used in the project is Cynara.
 In Tizen 3.0 checking if application has privilege to call method has been moved to C++ layer. It&#39;s the
@@ -572,13 +646,66 @@ if (!result) {
 
 ReportSuccess(data, out);
 </code></pre>
+<h3 id="implementation-c/dependencies-between-plugins">Dependencies between plugins</h3>
+<p>To allow using methods from module <code>A</code> in module <code>B</code>, you need to add dependencies in <code>&lt;pluginname&gt;.gyp</code> files
+and add <code>XW_EXPORT</code> macro to the definition of methods in module <code>A</code>.</p>
+<p>In below example, linking <code>GetNotiHandleFromJson</code> method of <code>CommonNotification</code> class in module <code>Notification</code>
+is added to the <code>Alarm</code> module.</p>
+<ol>
+<li>Add dependency in <code>.gyp</code> file in module <code>B</code>, in this example it is <code>alarm.gyp</code>:<pre class="prettyprint linenums"><code>&#39;dependencies&#39;: [
+&#39;../common/common.gyp:tizen_common&#39;,
+&#39;../notification/notification.gyp:tizen_notification&#39;,  # add this line
+],
+</code></pre></li>
+<li>Add <code>XW_EXPORT</code> macro available in <code>src/common/XW_Extension.h</code> file to the definition of method from module <code>A</code>:<pre class="prettyprint linenums"><code class="lang-cpp">class UserNotification : public CommonNotification {
+// ...
+XW_EXPORT static common::PlatformResult GetNotiHandleFromJson(const picojson::value&amp; noti_val,
+                                                           bool is_update,
+                                                           notification_h* noti_handle);
+// ...
+}
+</code></pre>
+</li>
+<li>Add dependency in <code>.gyp</code> file in module <code>A</code>, in this example it is <code>notification.gyp</code>:<pre class="prettyprint linenums"><code>{
+&#39;includes&#39;: [
+ &#39;../common/common.gypi&#39;,
+],
+&#39;targets&#39;: [
+ {
+   &#39;target_name&#39;: &#39;tizen_notification&#39;,
+   &#39;type&#39;: &#39;loadable_module&#39;,
+   &#39;dependencies&#39;: [
+     &#39;../common/common.gyp:tizen_common&#39;,
+   ],
+   &#39;sources&#39;: [
+     # ...
+   ],
+   &#39;conditions&#39;: [
+     # ...
+   ],
+   &#39;direct_dependent_settings&#39;: {  # add this property
+     &#39;libraries&#39;: [
+       &#39;-ltizen_notification&#39;,
+     ],
+   },
+ },
+],
+}
+</code></pre></li>
+</ol>
+<p>To make sure you did the good work, you can list dynamic dependencies of given <code>.so</code> file with the <code>ldd</code> command:</p>
+<pre><code class="lang-sh">sh-user-3.2# ldd /usr/lib/tizen-extensions-crosswalk/libtizen_alarm.so | grep noti
+ldd: warning: you do not have execution permission for `/usr/lib/tizen-extensions-crosswalk/libtizen_alarm.so&#39;
+libtizen_notification.so =&gt; /usr/lib/tizen-extensions-crosswalk/libtizen_notification.so (0xb6e52000)  # OK!
+libnotification.so.0 =&gt; /lib/libnotification.so.0 (0xb6c93000)
+</code></pre>
 <h3 id="implementation-c/asynchronous-calls">Asynchronous calls</h3>
 <p>To perform asynchronous request <code>common::TaskQueue</code> component should be used.
 You should use lambda expression which calls business logic and passes result to
 JavaScript layer by calling <code>PostMessage(const char* msg)</code>.</p>
 <p>Asynchronous response is not matched to request automatically. You should pass
 <code>callbackId</code> received from JavaScript layer as an argument. It allows to
-call the appropriate user callback in JS async message handler.</p>
+call the appropriate user callback in JavaScript async message handler.</p>
 <pre class="prettyprint linenums"><code class="lang-cpp">auto search = [this, args]() -&gt; void {
 
   // business logic
@@ -635,8 +762,14 @@ LoggerI(&quot;Data size: %d&quot;, object-&gt;data-&gt;size);
 LoggerW(&quot;Data in %s object is empty&quot;, object-&gt;name);
 LoggerE(&quot;Error occurred while getting data [%d]&quot;, error);
 </code></pre>
+<p>Upon entering and leaving function&#39;s scope, a message should be printed with <code>DEBUG</code> priority using <code>ScopeLogger</code> macro:</p>
+<pre class="prettyprint linenums"><code class="lang-cpp">// print simply, default &quot;Enter&quot; log
+ScopeLogger();
+// print more detailed message
+ScopeLogger(&quot;state: %d; err: %s&quot;, (int) state, err);
+</code></pre>
 <h3 id="implementation-c/error-handling">Error handling</h3>
-<p>Regarding to <a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Exceptions">Google C++ Style Guide</a> we do not use Exceptions.</p>
+<p>Regarding to <a href="https://google.github.io/styleguide/cppguide.html#Exceptions">Google C++ Style Guide</a> we do not use Exceptions.</p>
 <p>To deliver error conditions to JavaScript layer, that can occur in the platform,
 <code>LogAndReportError</code> or <code>ReportError</code> method should be used. All available error codes are defined
 in <code>common/platform_result.h</code></p>
@@ -828,6 +961,1220 @@ After build and installation webapi-plugins-test <code>webapis.test</code> names
 <pre class="prettyprint linenums"><code class="lang-javascript">var test = webapis.test.ping();
 console.log(test); // Hello!
 </code></pre>
+<h2 id="appendices">Appendices</h2>
+<h3 id="appendices/appendix-a-type-conversion-tables">Appendix A - type conversion tables</h3>
+<h4 id="type-conversion-tables">Type conversion tables</h4>
+<p>Below tables present convertions, which are performed by <code>validateArgs</code> method in
+<code>src/utils/utils_api.js</code> file before sending data to C++ layer.</p>
+<ul>
+<li>Boolean</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>false</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>false</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>NaN</td>
+<td>false</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.POSITIVE_INFINITY</td>
+<td>true</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.NEGATIVE_INFINITY</td>
+<td>true</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-1</td>
+<td>true</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>false</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>1</td>
+<td>true</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>3.14</td>
+<td>true</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;&quot; (Empty String)</td>
+<td>false</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;0&quot;</td>
+<td>true</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;TIZEN&quot;</td>
+<td>true</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{ name : &quot;TIZEN&quot; }</td>
+<td>true</td>
+</tr>
+<tr>
+<td>Function Object</td>
+<td>function () { }</td>
+<td>true</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>Number : long</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>0</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>true</td>
+<td>1</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>false</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>NaN</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.POSITIVE_INFINITY</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.NEGATIVE_INFINITY</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-1</td>
+<td>-1</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>1</td>
+<td>1</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>3.14</td>
+<td>3</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;&quot; (Empty String)</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;-1&quot;</td>
+<td>-1</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;0&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;1&quot;</td>
+<td>1</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;3.14&quot;</td>
+<td>3</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;TIZEN&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{ name : &quot;TIZEN&quot; }</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Function Object</td>
+<td>function () { }</td>
+<td>0</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>Number : unsigned long</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>0</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>true</td>
+<td>1</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>false</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>NaN</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.POSITIVE_INFINITY</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.NEGATIVE_INFINITY</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-1</td>
+<td>4294967295</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>1</td>
+<td>1</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>3.14</td>
+<td>3</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;&quot; (Empty String)</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;-1&quot;</td>
+<td>4294967295</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;0&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;1&quot;</td>
+<td>1</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;TIZEN&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{ name : &quot;TIZEN&quot; }</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Function Object</td>
+<td>function () { }</td>
+<td>0</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>Number : unsigned long long</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>0</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>true</td>
+<td>1</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>false</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>NaN</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.POSITIVE_INFINITY</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.NEGATIVE_INFINITY</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-1</td>
+<td>18446744073709551615</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>1</td>
+<td>1</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>3.14</td>
+<td>3</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;&quot; (Empty String)</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;-1&quot;</td>
+<td>18446744073709551615</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;0&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;1&quot;</td>
+<td>1</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;TIZEN&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{ name : &quot;TIZEN&quot; }</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Function Object</td>
+<td>function () { }</td>
+<td>0</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>Number : byte [-128, 127]</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>0</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>true</td>
+<td>1</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>false</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>NaN</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.POSITIVE_INFINITY</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.NEGATIVE_INFINITY</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-1</td>
+<td>-1</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>1</td>
+<td>1</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>3.14</td>
+<td>3</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-128</td>
+<td>-128</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-192</td>
+<td>64</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-256</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>127</td>
+<td>127</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>128</td>
+<td>-128</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>256</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;&quot; (Empty String)</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;0&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;1&quot;</td>
+<td>1</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;256&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;TIZEN&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{ name : &quot;TIZEN&quot; }</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Function Object</td>
+<td>function () { }</td>
+<td>0</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>Number : double</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>true</td>
+<td>1</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>false</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>NaN</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.POSITIVE_INFINITY</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.NEGATIVE_INFINITY</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-1</td>
+<td>-1</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>1</td>
+<td>1</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>3.14</td>
+<td>3.14</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;&quot; (Empty String)</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;0&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;-3.14&quot;</td>
+<td>-3.14</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;3.14&quot;</td>
+<td>3.14</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;TIZEN&quot;</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{ name : &quot;TIZEN&quot; }</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Function Object</td>
+<td>function () { }</td>
+<td>TypeMismatchError</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>String</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>&quot;undefined&quot;</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>&quot;null&quot;</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>true</td>
+<td>&quot;true&quot;</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>false</td>
+<td>&quot;false&quot;</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>NaN</td>
+<td>&quot;NaN&quot;</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.POSITIVE_INFINITY</td>
+<td>&quot;Infinity&quot;</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.NEGATIVE_INFINITY</td>
+<td>&quot;-Infinity&quot;</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-1</td>
+<td>&quot;-1&quot;</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>&quot;0&quot;</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>1</td>
+<td>&quot;1&quot;</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>3.14</td>
+<td>&quot;3.14&quot;</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{ }</td>
+<td>&quot;[object Object]&quot;</td>
+</tr>
+<tr>
+<td>Function Object</td>
+<td>function () { }</td>
+<td>&quot;function () { }&quot;</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>Platform Object</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>nullable: null; non-nullable: TypeMismatchError</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>true</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>false</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>NaN</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;TIZEN&quot;</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{}</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Function Object</td>
+<td>function () { }</td>
+<td>TypeMismatchError</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>Function Object</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>nullable: null; non-nullable: TypeMismatchError</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>true</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>false</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>NaN</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;TIZEN&quot;</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{ }</td>
+<td>TypeMismatchError</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>Array Object</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>nullable: null; non-nullable: TypeMismatchError</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>true</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>false</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>NaN</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;TIZEN&quot;</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{ }</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Function Object</td>
+<td>function () { }</td>
+<td>TypeMismatchError</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>Dictionary</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+<th>Comment</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>nullable: null; non-nullable: TypeMismatchError</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>true</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>false</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>NaN</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;TIZEN&quot;</td>
+<td>TypeMismatchError</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{ }</td>
+<td>{}</td>
+<td>No exception is thrown</td>
+</tr>
+<tr>
+<td>Function Object</td>
+<td>function () { }</td>
+<td>function () { }</td>
+<td>No exception is thrown</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>Octet [0, 255]</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>0</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>true</td>
+<td>1</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>false</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>NaN</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.POSITIVE_INFINITY</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>Number.NEGATIVE_INFINITY</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-1</td>
+<td>255</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>1</td>
+<td>1</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>3.14</td>
+<td>3</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-128</td>
+<td>128</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-192</td>
+<td>64</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>-256</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>256</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;&quot; (Empty String)</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;0&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;1&quot;</td>
+<td>1</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;256&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;TIZEN&quot;</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{ name : &quot;TIZEN&quot; }</td>
+<td>0</td>
+</tr>
+<tr>
+<td>Function Object</td>
+<td>function () { }</td>
+<td>0</td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>Enum</li>
+</ul>
+<table class="table table-striped">
+<thead>
+<tr>
+<th>Input Type</th>
+<th>Input Value</th>
+<th>Result</th>
+<th>Comment</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>undefined</td>
+<td>undefined</td>
+<td>TypeMismatchError</td>
+<td>unless &quot;undefined&quot; is on the list of the Enum values</td>
+</tr>
+<tr>
+<td>null</td>
+<td>null</td>
+<td>TypeMismatchError</td>
+<td>unless &quot;null&quot; is one of the Enum values</td>
+</tr>
+<tr>
+<td>Number</td>
+<td>0</td>
+<td>TypeMismatchError</td>
+<td>unless &quot;0&quot; is one of the Enum values</td>
+</tr>
+<tr>
+<td>Boolean</td>
+<td>true</td>
+<td>TypeMismatchError</td>
+<td>unless &quot;true&quot; is one of the Enum values</td>
+</tr>
+<tr>
+<td>String</td>
+<td>&quot;TIZEN&quot;</td>
+<td>TypeMismatchError</td>
+<td>unless &quot;TIZEN&quot; is one of the Enum values</td>
+</tr>
+<tr>
+<td>String</td>
+<td>any of the Enum values</td>
+<td>given string</td>
+<td>Enum defines valid values, any of those values can be used and are accepted without conversion</td>
+</tr>
+<tr>
+<td>Object</td>
+<td>{ }</td>
+<td>TypeMismatchError</td>
+</tr>
+</tbody>
+</table>
+<h3 id="appendices/appendix-b-javascript-code-example-style-guide">Appendix B - Javascript code example style guide</h3>
+<h4 id="code-example-style-guide">Code Example Style Guide</h4>
+<p>Below guide lists rules of writing example code placed in the WIDL files.</p>
+<p><strong>Whitespaces</strong></p>
+<ul>
+<li>Use only spaces (do not use tabs), one level indent has two spaces</li>
+<li>No whitespace at the end of line</li>
+<li>One extra space after keywords which use round brackets (if, for, while, switch, catch, …)</li>
+<li>Add space between variables and operators</li>
+<li>Initialization lists<ul>
+<li>Space after colon but not before</li>
+<li>Space after comma</li>
+</ul>
+</li>
+</ul>
+<p><strong>Comments</strong></p>
+<ul>
+<li>Use double slash // (do not use /<em> </em>/)</li>
+<li>Start sentence with capital letter</li>
+<li>Do not use dot at the end</li>
+</ul>
+<pre class="prettyprint linenums"><code class="lang-js">// This is a simple comment
+</code></pre>
+<p><strong>Brackets</strong></p>
+<ul>
+<li>Body brackets<ul>
+<li>Opening and closing brackets in new lines</li>
+</ul>
+</li>
+<li>No extra whitespace inside brackets (after opening nor before closing)</li>
+</ul>
+<pre class="prettyprint linenums"><code class="lang-js">try
+{
+  var messages = [&quot;A&quot;, &quot;B&quot;];
+}
+catch (err)
+{
+  console.log(&quot;Error: &quot; + err.message);
+}
+</code></pre>
+<p><strong>Strings</strong></p>
+<ul>
+<li>Use only quotation marks (“), do not use apostrophes (‘) to create strings</li>
+</ul>
+<p><strong>console.log()</strong></p>
+<ul>
+<li>Start log with capital letter</li>
+<li>Do not use dots</li>
+<li>Add space after colon</li>
+</ul>
+<pre class="prettyprint linenums"><code class="lang-js">console.log(“This is example error: “ + err.message);
+</code></pre>
+<p><strong>Multi-line</strong></p>
+<ul>
+<li>Each line should not be more than 100 characters long</li>
+<li>Indentation in second line must match opening bracket</li>
+</ul>
+<pre class="prettyprint linenums"><code class="lang-js">console.log(&quot;This is console log information error: &quot; + error.message +
+            &quot; and there is more”);
+</code></pre>
+<p><strong>Functions with function as an argument</strong></p>
+<ul>
+<li>Name of the function should be written in line with previous function&#39;s closing bracket</li>
+<li>Other parameters can be put in the same line as function&#39;s closing bracket</li>
+</ul>
+<pre class="prettyprint linenums"><code class="lang-js">functionCalculate(&quot;First argument&quot;, function(e)
+{
+  console.log(&quot;Information: &quot; + e.message);
+}, function(e)
+{
+  console.log(&quot;Error: &quot; + e.message);
+}, &quot;Last argument&quot;);
+</code></pre>
+<p><strong>Statement separation</strong></p>
+<ul>
+<li>Each statement has to be in new line and has to end with semicolon</li>
+</ul>
 
 </div>
 <script src="js/mootools-yui-compressed.js"></script>
index 2a7a069..7ead273 100644 (file)
@@ -1,6 +1,6 @@
 {
   "name": "WebApiGuidelines",
-  "version": "0.3.0",
+  "version": "0.7.0",
   "dependencies": {
     "doctor-md": "git://github.com/Hagith/doctor.git#print-css"
   },
diff --git a/doc/src/appendices.md b/doc/src/appendices.md
new file mode 100644 (file)
index 0000000..c4ab246
--- /dev/null
@@ -0,0 +1 @@
+## Appendices
diff --git a/doc/src/appendix_a.md b/doc/src/appendix_a.md
new file mode 100644 (file)
index 0000000..fea5a18
--- /dev/null
@@ -0,0 +1,259 @@
+### Appendix A - type conversion tables
+
+#### Type conversion tables
+
+Below tables present convertions, which are performed by ``validateArgs`` method in
+``src/utils/utils_api.js`` file before sending data to C++ layer.
+
+* Boolean
+
+|Input Type|Input Value|Result|
+|----------|-----------|------|
+|undefined|undefined|false|
+|null|null|false|
+|Number|NaN|false|
+|Number|Number.POSITIVE_INFINITY|true|
+|Number|Number.NEGATIVE_INFINITY|true|
+|Number|-1|true|
+|Number|0|false|
+|Number|1|true|
+|Number|3.14|true|
+|String|"" (Empty String)|false|
+|String|"0"|true|
+|String|"TIZEN"|true|
+|Object|{ name : "TIZEN" }|true|
+|Function Object|function () { }|true|
+
+* Number : long
+
+|Input Type|Input Value|Result|
+|----------|-----------|------|
+|undefined|undefined|0|
+|null|null|0|
+|Boolean|true|1|
+|Boolean|false|0|
+|Number|NaN|0|
+|Number|Number.POSITIVE_INFINITY|0|
+|Number|Number.NEGATIVE_INFINITY|0|
+|Number|-1|-1|
+|Number|0|0|
+|Number|1|1|
+|Number|3.14|3|
+|String|"" (Empty String)|0|
+|String|"-1"|-1|
+|String|"0"|0|
+|String|"1"|1|
+|String|"3.14"|3|
+|String|"TIZEN"|0|
+|Object|{ name : "TIZEN" }|0|
+|Function Object|function () { }|0|
+
+* Number : unsigned long
+
+|Input Type|Input Value|Result|
+|----------|-----------|------|
+|undefined|undefined|0|
+|null|null|0|
+|Boolean|true|1|
+|Boolean|false|0|
+|Number|NaN|0|
+|Number|Number.POSITIVE_INFINITY|0|
+|Number|Number.NEGATIVE_INFINITY|0|
+|Number|-1|4294967295|
+|Number|0|0|
+|Number|1|1|
+|Number|3.14|3|
+|String|"" (Empty String)|0|
+|String|"-1"|4294967295|
+|String|"0"|0|
+|String|"1"|1|
+|String|"TIZEN"|0|
+|Object|{ name : "TIZEN" }|0|
+|Function Object|function () { }|0|
+
+* Number : unsigned long long
+
+|Input Type|Input Value|Result|
+|----------|-----------|------|
+|undefined|undefined|0|
+|null|null|0|
+|Boolean|true|1|
+|Boolean|false|0|
+|Number|NaN|0|
+|Number|Number.POSITIVE_INFINITY|0|
+|Number|Number.NEGATIVE_INFINITY|0|
+|Number|-1|18446744073709551615|
+|Number|0|0|
+|Number|1|1|
+|Number|3.14|3|
+|String|"" (Empty String)|0|
+|String|"-1"|18446744073709551615|
+|String|"0"|0|
+|String|"1"|1|
+|String|"TIZEN"|0|
+|Object|{ name : "TIZEN" }|0|
+|Function Object|function () { }|0|
+
+* Number : byte [-128, 127]
+
+|Input Type|Input Value|Result|
+|----------|-----------|------|
+|undefined|undefined|0|
+|null|null|0|
+|Boolean|true|1|
+|Boolean|false|0|
+|Number|NaN|0|
+|Number|Number.POSITIVE_INFINITY|0|
+|Number|Number.NEGATIVE_INFINITY|0|
+|Number|-1|-1|
+|Number|0|0|
+|Number|1|1|
+|Number|3.14|3|
+|Number|-128|-128|
+|Number|-192|64|
+|Number|-256|0|
+|Number|127|127|
+|Number|128|-128|
+|Number|256|0|
+|String|"" (Empty String)|0|
+|String|"0"|0|
+|String|"1"|1|
+|String|"256"|0|
+|String|"TIZEN"|0|
+|Object|{ name : "TIZEN" }|0|
+|Function Object|function () { }|0|
+
+* Number : double
+
+|Input Type|Input Value|Result|
+|----------|-----------|------|
+|undefined|undefined|TypeMismatchError|
+|null|null|0|
+|Boolean|true|1|
+|Boolean|false|0|
+|Number|NaN|TypeMismatchError|
+|Number|Number.POSITIVE_INFINITY|TypeMismatchError|
+|Number|Number.NEGATIVE_INFINITY|TypeMismatchError|
+|Number|-1|-1|
+|Number|0|0|
+|Number|1|1|
+|Number|3.14|3.14|
+|String|"" (Empty String)|0|
+|String|"0"|0|
+|String|"-3.14"|-3.14|
+|String|"3.14"|3.14|
+|String|"TIZEN"|TypeMismatchError|
+|Object|{ name : "TIZEN" }|TypeMismatchError|
+|Function Object|function () { }|TypeMismatchError|
+
+* String
+
+|Input Type|Input Value|Result|
+|----------|-----------|------|
+|undefined|undefined|"undefined"|
+|null|null|"null"|
+|Boolean|true|"true"|
+|Boolean|false|"false"|
+|Number|NaN|"NaN"|
+|Number|Number.POSITIVE_INFINITY|"Infinity"|
+|Number|Number.NEGATIVE_INFINITY|"-Infinity"|
+|Number|-1|"-1"|
+|Number|0|"0"|
+|Number|1|"1"|
+|Number|3.14|"3.14"|
+|Object|{ }|"[object Object]"|
+|Function Object|function () { }|"function () { }"|
+
+* Platform Object
+
+|Input Type|Input Value|Result|
+|----------|-----------|------|
+|undefined|undefined|TypeMismatchError|
+|null|null|nullable: null; non-nullable: TypeMismatchError|
+|Boolean|true|TypeMismatchError|
+|Boolean|false|TypeMismatchError|
+|Number|NaN|TypeMismatchError|
+|Number|0|TypeMismatchError|
+|String|"TIZEN"|TypeMismatchError|
+|Object|{}|TypeMismatchError|
+|Function Object|function () { }|TypeMismatchError|
+
+* Function Object
+
+|Input Type|Input Value|Result|
+|----------|-----------|------|
+|undefined|undefined|TypeMismatchError|
+|null|null|nullable: null; non-nullable: TypeMismatchError|
+|Boolean|true|TypeMismatchError|
+|Boolean|false|TypeMismatchError|
+|Number|NaN|TypeMismatchError|
+|Number|0|TypeMismatchError|
+|String|"TIZEN"|TypeMismatchError|
+|Object|{ }|TypeMismatchError|
+
+* Array Object
+
+|Input Type|Input Value|Result|
+|----------|-----------|------|
+|undefined|undefined|TypeMismatchError|
+|null|null|nullable: null; non-nullable: TypeMismatchError|
+|Boolean|true|TypeMismatchError|
+|Boolean|false|TypeMismatchError|
+|Number|NaN|TypeMismatchError|
+|Number|0|TypeMismatchError|
+|String|"TIZEN"|TypeMismatchError|
+|Object|{ }|TypeMismatchError|
+|Function Object|function () { }|TypeMismatchError|
+
+* Dictionary
+
+|Input Type|Input Value|Result|Comment|
+|----------|-----------|------|-------|
+|undefined|undefined|TypeMismatchError|
+|null|null|nullable: null; non-nullable: TypeMismatchError|
+|Boolean|true|TypeMismatchError|
+|Boolean|false|TypeMismatchError|
+|Number|NaN|TypeMismatchError|
+|Number|0|TypeMismatchError|
+|String|"TIZEN"|TypeMismatchError|
+|Object|{ }|{}|No exception is thrown
+|Function Object|function () { }|function () { }|No exception is thrown
+
+* Octet [0, 255]
+
+|Input Type|Input Value|Result|
+|----------|-----------|------|
+|undefined|undefined|0|
+|null|null|0|
+|Boolean|true|1|
+|Boolean|false|0|
+|Number|NaN|0|
+|Number|Number.POSITIVE_INFINITY|0|
+|Number|Number.NEGATIVE_INFINITY|0|
+|Number|-1|255|
+|Number|0|0|
+|Number|1|1|
+|Number|3.14|3|
+|Number|-128|128|
+|Number|-192|64|
+|Number|-256|0|
+|Number|256|0|
+|String|"" (Empty String)|0|
+|String|"0"|0|
+|String|"1"|1|
+|String|"256"|0|
+|String|"TIZEN"|0|
+|Object|{ name : "TIZEN" }|0|
+|Function Object|function () { }|0|
+
+* Enum
+
+|Input Type|Input Value|Result|Comment|
+|----------|-----------|------|-------|
+|undefined|undefined|TypeMismatchError|unless "undefined" is on the list of the Enum values
+|null|null|TypeMismatchError|unless "null" is one of the Enum values
+|Number|0|TypeMismatchError|unless "0" is one of the Enum values
+|Boolean|true|TypeMismatchError|unless "true" is one of the Enum values
+|String|"TIZEN"|TypeMismatchError|unless "TIZEN" is one of the Enum values
+|String|any of the Enum values|given string|Enum defines valid values, any of those values can be used and are accepted without conversion
+|Object|{ }|TypeMismatchError|
diff --git a/doc/src/appendix_b.md b/doc/src/appendix_b.md
new file mode 100644 (file)
index 0000000..b725a8d
--- /dev/null
@@ -0,0 +1,85 @@
+### Appendix B - Javascript code example style guide
+
+#### Code Example Style Guide
+
+Below guide lists rules of writing example code placed in the WIDL files.
+
+**Whitespaces**
+
+- Use only spaces (do not use tabs), one level indent has two spaces
+- No whitespace at the end of line
+- One extra space after keywords which use round brackets (if, for, while, switch, catch, …)
+- Add space between variables and operators
+- Initialization lists
+  - Space after colon but not before
+  - Space after comma
+
+**Comments**
+
+- Use double slash // (do not use /* */)
+- Start sentence with capital letter
+- Do not use dot at the end
+
+```js
+// This is a simple comment
+```
+
+**Brackets**
+
+- Body brackets
+  - Opening and closing brackets in new lines
+- No extra whitespace inside brackets (after opening nor before closing)
+
+```js
+try
+{
+  var messages = ["A", "B"];
+}
+catch (err)
+{
+  console.log("Error: " + err.message);
+}
+```
+
+**Strings**
+
+- Use only quotation marks (“), do not use apostrophes (‘) to create strings
+
+**console.log()**
+
+- Start log with capital letter
+- Do not use dots
+- Add space after colon
+
+```js
+console.log(“This is example error: “ + err.message);
+```
+
+**Multi-line**
+
+- Each line should not be more than 100 characters long
+- Indentation in second line must match opening bracket
+
+```js
+console.log("This is console log information error: " + error.message +
+            " and there is more”);
+```
+
+**Functions with function as an argument**
+
+- Name of the function should be written in line with previous function's closing bracket
+- Other parameters can be put in the same line as function's closing bracket
+
+```js
+functionCalculate("First argument", function(e)
+{
+  console.log("Information: " + e.message);
+}, function(e)
+{
+  console.log("Error: " + e.message);
+}, "Last argument");
+```
+
+**Statement separation**
+
+- Each statement has to be in new line and has to end with semicolon
\ No newline at end of file
index 4e39a93..78fc78b 100644 (file)
@@ -6,10 +6,15 @@ C++, JavaScript
 
 ### Coding style
 
-Use Google style guide,
-C++: http://google-styleguide.googlecode.com/svn/trunk/cppguide.html
+Use Google style guides (with small exceptions):
 
-JavaScript: http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
+C++: https://google.github.io/styleguide/cppguide.html
+
+JavaScript: https://google.github.io/styleguide/jsguide.html
+
+On branches ```tizen_3.0``` and higher, the C++ ~~and JavaScript~~ files are formatted using scripts,
+which its usage is described in the [Format code](#tools/format-code) section of this document.
+The section also describes where the exceptions from Google coding style are defined.
 
 ### API guide
 
@@ -29,11 +34,11 @@ $ git clone ssh://<user.id>@168.219.209.56:29418/framework/web/webapi-plugins
 $ cd webapi-plugins
 $ git checkout origin/tizen_2.4
 ```
-For Tizen 3.0
+For Tizen 3.0 and higher
 ```sh
-$ git clone ssh://<user.id>@168.219.209.56:29418/framework/web/webapi-plugins
+$ git clone ssh://<user.id>@review.tizen.org:29418/platform/core/api/webapi-plugins && scp -p -P 29418 <user.id>@review.tizen.org:hooks/commit-msg webapi-plugins/.git/hooks/
 $ cd webapi-plugins
-$ git checkout origin/tizen_3.0
+$ git checkout origin/tizen_<tizen_version>
 ```
 
 ### License and Boilerplate
@@ -41,7 +46,7 @@ $ git checkout origin/tizen_3.0
 Use this boilerplate in every new created source files.
 ```sh
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) <year of file creation> 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.
index c6d84e5..7ea4fdd 100644 (file)
@@ -18,6 +18,15 @@ Example: If operation should change some object retrieved from platform,
 identifier should be passed again and additional check if object still exists
 should be made.
 
+According to [Google C++ Style Guide][3] static variables should **NOT** be used.
+
+This rule concerns especially to ```<pluginname>Manager```, ```<pluginname>Client```,
+```<pluginname>Server``` etc. classes, which tend to implement the Singleton design pattern.
+Because of this, the above mentioned classes' instances should **NOT** be declared as ``static``
+and should **NOT** be got through ``getInstance`` methods.
+Instead, the classes's instances should be declared as an ``private`` attribute of
+```<pluginname>Instance``` class.
+
 ### Privileges
 
 Some of the API methods require privilege access. The privilege engine used in the project is Cynara.
@@ -110,6 +119,68 @@ if (!result) {
 ReportSuccess(data, out);
 ```
 
+### Dependencies between plugins
+
+To allow using methods from module ``A`` in module ``B``, you need to add dependencies in ``<pluginname>.gyp`` files
+and add ``XW_EXPORT`` macro to the definition of methods in module ``A``.
+
+In below example, linking ``GetNotiHandleFromJson`` method of ``CommonNotification`` class in module ``Notification``
+is added to the ``Alarm`` module.
+
+1. Add dependency in ``.gyp`` file in module ``B``, in this example it is ``alarm.gyp``:
+```
+'dependencies': [
+  '../common/common.gyp:tizen_common',
+  '../notification/notification.gyp:tizen_notification',  # add this line
+],
+```
+2. Add ``XW_EXPORT`` macro available in ``src/common/XW_Extension.h`` file to the definition of method from module ``A``:
+```cpp
+class UserNotification : public CommonNotification {
+// ...
+XW_EXPORT static common::PlatformResult GetNotiHandleFromJson(const picojson::value& noti_val,
+                                                              bool is_update,
+                                                              notification_h* noti_handle);
+// ...
+}
+```
+3. Add dependency in ``.gyp`` file in module ``A``, in this example it is ``notification.gyp``:
+```
+{
+  'includes': [
+    '../common/common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'tizen_notification',
+      'type': 'loadable_module',
+      'dependencies': [
+        '../common/common.gyp:tizen_common',
+      ],
+      'sources': [
+        # ...
+      ],
+      'conditions': [
+        # ...
+      ],
+      'direct_dependent_settings': {  # add this property
+        'libraries': [
+          '-ltizen_notification',
+        ],
+      },
+    },
+  ],
+}
+```
+
+To make sure you did the good work, you can list dynamic dependencies of given ``.so`` file with the ``ldd`` command:
+```sh
+sh-user-3.2# ldd /usr/lib/tizen-extensions-crosswalk/libtizen_alarm.so | grep noti
+ldd: warning: you do not have execution permission for `/usr/lib/tizen-extensions-crosswalk/libtizen_alarm.so'
+libtizen_notification.so => /usr/lib/tizen-extensions-crosswalk/libtizen_notification.so (0xb6e52000)  # OK!
+libnotification.so.0 => /lib/libnotification.so.0 (0xb6c93000)
+```
+
 ### Asynchronous calls
 
 To perform asynchronous request ```common::TaskQueue``` component should be used.
@@ -118,7 +189,7 @@ JavaScript layer by calling ```PostMessage(const char* msg)```.
 
 Asynchronous response is not matched to request automatically. You should pass
 ```callbackId``` received from JavaScript layer as an argument. It allows to
-call the appropriate user callback in JS async message handler.
+call the appropriate user callback in JavaScript async message handler.
 
 ```cpp
 auto search = [this, args]() -> void {
@@ -184,6 +255,16 @@ LoggerW("Data in %s object is empty", object->name);
 LoggerE("Error occurred while getting data [%d]", error);
 ```
 
+Upon entering and leaving function's scope, a message should be printed with ```DEBUG``` priority using ``ScopeLogger`` macro:
+
+```cpp
+// print simply, default "Enter" log
+ScopeLogger();
+// print more detailed message
+ScopeLogger("state: %d; err: %s", (int) state, err);
+```
+
+
 ### Error handling
 
 Regarding to [Google C++ Style Guide][2] we do not use Exceptions.
@@ -210,4 +291,5 @@ if (native_.isFailure(ret)) {
 ```
 
   [1]: http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)
-  [2]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Exceptions
+  [2]: https://google.github.io/styleguide/cppguide.html#Exceptions
+  [3]: https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
index 569060d..4e7ca43 100644 (file)
@@ -1,10 +1,9 @@
 ## Implementation - JavaScript
 
 Each plugin contains JavaScript files. This is the place where user input is
-being processed validated before send to C++ layer.
+being processed validated before sending to C++ layer.
 
-Badge API will be used to show the creation of JavaScript file (lot of content
-of this file will be already generated via Stub Generator).
+Badge API will be used to show the creation of JavaScript file.
 
 ### Interface creation
 
@@ -89,13 +88,13 @@ var number = converter_.toLong(result);
 #### Validator
 
 When API JavaScript method is called first thing that has to be done in
-JavaScript layer of api implementation is to process and validate arguments
+JavaScript layer of API implementation is to process and validate arguments
 given by the user. The process of validation consists of ensuring that the
 proper amount of arguments was given and that they were of the expected
 type and throwing exception if necessary.
 
 Validator helps to ensure that user sent proper values. Validator is available
-at ```xwalk.utils.validator``` and predefined js types at ```xwalk.utils.validator.types```
+at ```xwalk.utils.validator``` and predefined JavaScript types at ```xwalk.utils.validator.types```
 
 Below can be found example of using validator inside ```setBadgeCount``` method
 that requires appId in form of string and long count value:
@@ -110,6 +109,11 @@ var args = validator_.validateArgs(arguments, [
 ]);
 ```
 
+The ``validateArgs`` method may also validate optional and nullable arguments.
+See its definition in file ``src/utils/utils_api.js``.
+
+This method respecting the JavaScript type conversion rules is presented [the Appendix A - type conversion tables](#appendices/appendix-a-type-conversion-tables).
+
 ### Exceptions
 
 At some point whether improper data is received or given to JavaScript might
@@ -124,6 +128,9 @@ throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR,
 WebAPIException constructor takes as argument the type of error to be thrown.
 The second additional argument is error message.
 
+There might be a need to throw expception because of failure received from C++ layer,
+for this case see below section.
+
 ### Synchronous methods
 
 In order to perform synchronous operation (one that does not require callback
@@ -149,9 +156,9 @@ Result is assigned to ret variable.
 
 In order to work with method that requires callback instead of callSync(),
 call() method needs to be called. Apart from the first two arguments that are
-exactly the same as in call() method (c++ method binding, object) it takes
+exactly the same as in callSync() method (C++ method binding, object) it takes
 additional argument that is a function that will be called when the native
-call is processed:
+call response is processed:
 
 ```js
 var native_ = new xwalk.utils.NativeManager(extension);
index 12d50f4..84bd52a 100644 (file)
@@ -11,6 +11,7 @@
 | 0.5.0 | 2015-06-18 | Devel package | Pawel Kaczmarek<br><p.kaczmarek3@samsung.com> |
 | 0.5.1 | 2015-06-24 | Add info about WAPIOven.py | Pawel Kaczmarek<br><p.kaczmarek3@samsung.com> |
 | 0.6.0 | 2016-10-28 | update devel package for tizen 3.0 | Annie Park<br><hj.na.park@samsung.com> |
+| 0.7.0 | 2017-11-09 | Update guidelines for Tizen 4.0 | Szymon Jastrzębski<br><s.jastrzebsk@partner.samsung.com> |
 
 ## Overview
 This document should be used as a guideline for developers who are creating web
@@ -25,3 +26,6 @@ Each plugin should be written with great attention on JavaScript.
 {{>src/implementation_js.md}}
 {{>src/implementation_cc.md}}
 {{>src/devel_package.md}}
+{{>src/appendices.md}}
+{{>src/appendix_a.md}}
+{{>src/appendix_b.md}}
\ No newline at end of file
index 161b0d4..ac1dcce 100644 (file)
@@ -14,16 +14,29 @@ Each plugin contains following structure:
 * ```<pluginname>_instance.h```
 * ```<pluginname>_instance.cc```
 
+Additionally, plugins may contain below structure, depending on the WIDL specification file:
+* ```<pluginname>_client.h```
+* ```<pluginname>_client.cc```
+* ```<pluginname>_server.h```
+* ```<pluginname>_server.cc```
+* ```<pluginname>_service.h```
+* ```<pluginname>_service.cc```
+* ```<pluginname>_util.h```
+* ```<pluginname>_util.cc```
+
+and other files with similar naming-convention needed by the developer.
+
+
 ### Spec file
 
 Spec file (```webapi-plugins.spec```) kept inside ```packaging/``` directory
-is build specification file used by RPM packaging system where variables are defined.
+is build specification file used by RPM packaging system where variables are defined.
 Those variables can be used to include or exclude particular modules from
 build for each profile (mobile, TV, wearable).
 
 ### Manifest file
 
-Each RPM package must have a manifest file where developers can specify the access control domain
+Each RPM package must have a manifest file, where developers can specify the access control domain
 in which their application should be running and potentially additional security policies for the
 application. It is necessary to build the project. The manifest file (```webapi-plugins.manifest```)
 is located in the root directory of the project.
@@ -47,7 +60,7 @@ Description of files required in plugin implementation.
   This file contains all methods required by each API.
   All operation should be done by JavaScript as much as possible.
   If JavaScript can do something, it should do it.
-  This file is responsible for checking arguments, calling C++ methods etc.
+  This file is responsible for checking and validating arguments, calling C++ methods etc.
 
 ### Plugin flow
 
@@ -58,7 +71,30 @@ Explanation of steps:
    This information consists of type of call (asynchronous, synchronous)
    arguments given by user, any additional information that is required to
    successfully acquire required data. Data is sent in form of JSON.
-2. C++ parses acquired JSON. After the data is processed. Appropriate platform
+2. C++ parses acquired JSON. After the data is processed, appropriate platform
    functions are called with the specified arguments.
 3. Platform returns specified values to C++ layer.
 4. Another JSON is formed. It consists of data that was acquired from platform.
+   The data is sent to JavaScript layer.
+
+### Tizen Unified
+
+With Tizen 4.0 an idea of Tizen Unified was introduced.
+
+Before Tizen 4.0, each profile specified in ``.gbs.conf`` file defined the package repositories
+for a single device type and a particular architecture.
+
+Since Tizen 4.0, each GBS profile is associated with a particular architecture and all device types.
+
+Each device with given profile and architecture requires to have at least 2 RPM files installed:
+```sh
+webapi-plugins-x.y-z.ARCH.rpm
+webapi-plugins-profile_PROFILE_NAME-x.y-z.ARCH.rpm
+```
+
+However, emulators require to have 3 RPM files installed:
+```sh
+webapi-plugins-x.y-z.i686.rpm
+webapi-plugins-profile_PROFILE_NAME-x.y-z.i686.rpm
+webapi-plugins-PROFILE_NAME-extension-emulator-x.y-z.i686.rpm
+```
index 1836f6e..2ceb3b7 100644 (file)
@@ -2,6 +2,8 @@
 
 ### Generate stub code
 
+#### <span style="color:red">**The generator is no longer maintained.**</span>
+
 To generate stub files from the widl you can use stub generator located in
 ```tools/skeleton_generator/``` directory and run the python command:
 
@@ -36,7 +38,7 @@ WIDL files can be found in the project repository:
 $ git clone ssh://<username>@168.219.209.56:29418/doc/web-device-api
 ```
 
-The widl files are placed in: ```web-device-api/web/widl/tizen/```
+The widl files are placed in: ```web-device-api/web/widl/tizen/``` directory.
 
 Stub files generated by above command:
 
@@ -72,3 +74,38 @@ Inside ```<pluginname>_api.js``` required JavaScript files should be added:
 To merge all JavaScript files ```tools/mergejs.py``` file is used.
 This script merge all files mentioned in ```<pluginname>_api.js``` file into one
 file before build process.
+
+
+### Format code
+
+To format code use scripts provided in the ``tools/codestyle`` directory.
+
+``cpplint`` is used to validate C++ and ``eslint`` for JavaScript files.
+
+**Currently, the JavaScript validator and formatter seems to be a little buggy,
+thus it is not recommended to use.**
+
+The developer needs to have ``python``, ``node.js``, ``eslint``, ``Closure Linter`` and ``clang-format`` installed.
+
+It is worth to make life easier by creating symbolic link to ``clang-format``.
+```sh
+sudo ln -s /usr/bin/clang-format-<clang format version> /usr/bin/clang-format
+```
+
+For convenience, in the root of the project links were provided for easier access:
+- ``code_format -> tools/codestyle/code_formatter.sh``
+- ``code_validate -> tools/codestyle/code_validation.sh``
+
+Those scripts consist of configuration for rules regarding the Google style guides, with few exceptions.
+
+To format and validate C++ and JavaScript code run in the root of the project:
+```sh
+./code_validate -a # -a for all, -c for C++, -js for JavaScript files
+./code_format -a   # use -h or --help for help
+```
+The scripts also accept a path to module's directory.
+By default every directory module in the ``src`` directory is used.
+
+For more details, please see ``tools/codestyle/README`` file.
+
+This rule concerns to branches ``tizen_3.0`` and above.
index 703958f..fb8166c 100644 (file)
@@ -39,7 +39,7 @@ In interface definition you can put following members:
   can be changed, if it is not read only.
 * Operation: Interface member, which represents method inside object.
   It is a function of programming language, which can be executed and returns a result.
-* Special operation: Performs a specific task. i.e. deleter, getter
+* Special operation: Performs a specific task. i.e. deleter, getter.
 * Static operation: It is not called for a specific instance of the interface,
   is called for static object regardless of an instance creation.
   It is connected with the interface itself.
@@ -72,8 +72,8 @@ Tizen implements ManagerObject
 
 To provide actual implementations of ManagerObject, instance of its Manager
 interface definition has to be made. Inside this Manager interface all attributes
-and functions that will be available form manager namespace, should be defined.
-There can be attributes which are other interfaces, operations and everything
+and functions that will be available from manager namespace, should be defined.
+There can be attributes, which are other interfaces, operations and everything
 that interfaces allows.
 
 Additional interface can be available as a standalone types not connected to
@@ -118,6 +118,11 @@ lacks of keyword ```FunctionOnly```.
 };
 ```
 
+### Example code style
+
+Coding style for example codes put in the between ``\code``  and ``\endcode`` tags
+should be written with respect to rules described in [the Appendix B](#appendices/appendix-b-javascript-code-example-style-guide).
+
 ### Example
 
 Example of WIDL file:
index 45abf6a..fe0d337 100644 (file)
@@ -1,7 +1,5 @@
 %bcond_with wayland
 
-%{!?profile:%define profile tv}
-
 %define _manifestdir %{TZ_SYS_RW_PACKAGES}
 %define _desktop_icondir %{TZ_SYS_SHARE}/icons/default/small
 
@@ -17,354 +15,349 @@ Group:      Development/Libraries
 Summary:    Tizen Web APIs implemented
 Source0:    %{name}-%{version}.tar.gz
 
-%ifarch %{arm} aarch64
-# ARM
-%define tizen_is_emulator           0
-%else
-# I586
-%define tizen_is_emulator           1
-%endif
-
-%if "%{_repository}" == "arm64-wayland"
-# 64bit
-%define tizen_is_arm64           1
-%else
-# 32bit
-%define tizen_is_arm64           0
-%endif
-
 ####################################################################
 #       Common Profile : artik                                     #
 ####################################################################
-%if "%{?profile}" == "common"
-
-%define tizen_privilege_engine                        CYNARA
-
-%define tizen_feature_account_support                 0
-%define tizen_feature_alarm_support                   1
-%define tizen_feature_app_control_settings_support    1
-%define tizen_feature_application_support             1
-%define tizen_feature_archive_support                 0
-%define tizen_feature_badge_support                   0
-%define tizen_feature_bluetooth_support               1
-%define tizen_feature_bookmark_support                0
-%define tizen_feature_calendar_support                0
-%define tizen_feature_contact_support                 0
-%define tizen_feature_content_support                 1
-%define tizen_feature_datacontrol_support             0
-%define tizen_feature_datasync_support                0
-%define tizen_feature_download_support                1
-%define tizen_feature_exif_support                    1
-%define tizen_feature_feedback_support                0
-%define tizen_feature_filesystem_support              1
-%define tizen_feature_fm_radio_support                0
-%define tizen_feature_ham_support                     0
-%define tizen_feature_iotcon_support                  0
-%define tizen_feature_location_batch                  0
-%define tizen_feature_key_manager_support             0
-%define tizen_feature_media_controller_support        0
-%define tizen_feature_media_key_support               0
-%define tizen_feature_message_port_support            1
-%define tizen_feature_messaging_support               0
-%define tizen_feature_nfc_emulation_support           0
-%define tizen_feature_nfc_support                     0
-%define tizen_feature_notification_support            0
-%define tizen_feature_package_support                 1
-%define tizen_feature_player_util_support             0
-%define tizen_feature_power_support                   0
-%define tizen_feature_preference_support              0
-%define tizen_feature_push_support                    0
-%define tizen_feature_se_support                      0
-%define tizen_feature_sensor_support                  0
-%define tizen_feature_sound_support                   1
-%define tizen_feature_system_info_support             1
-%define tizen_feature_system_setting_support          0
-%define tizen_feature_telephony_support               0
-%define tizen_feature_time_support                    1
-%define tizen_feature_web_setting_support             0
-%define tizen_feature_widget_service_support          0
-%define tizen_feature_wi_fi_support                   1
-%define tizen_feature_inputdevice_support             0
-%define tizen_feature_callhistory_support             0
-%define tizen_feature_nbs_support                     0
-%define tizen_feature_tvinputdevice_support           0
-
-%endif # tizen_profile_common
+
+%define tizen_common_privilege_engine                        CYNARA
+
+%define tizen_common_feature_account_support                 0
+%define tizen_common_feature_alarm_support                   1
+%define tizen_common_feature_app_control_settings_support    1
+%define tizen_common_feature_application_support             1
+%define tizen_common_feature_archive_support                 0
+%define tizen_common_feature_badge_support                   0
+%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_contact_support                 0
+%define tizen_common_feature_content_support                 1
+%define tizen_common_feature_datacontrol_support             0
+%define tizen_common_feature_datasync_support                0
+%define tizen_common_feature_download_support                1
+%define tizen_common_feature_exif_support                    1
+%define tizen_common_feature_feedback_support                0
+%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_iotcon_support                  0
+%define tizen_common_feature_location_batch                  0
+%define tizen_common_feature_key_manager_support             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_nfc_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_preference_support              0
+%define tizen_common_feature_push_support                    0
+%define tizen_common_feature_se_support                      0
+%define tizen_common_feature_sensor_support                  0
+%define tizen_common_feature_sound_support                   1
+%define tizen_common_feature_system_info_support             1
+%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
+
 
 ####################################################################
 #       Mobile Profile :  TM1(32bit), Redwood(SM-Z910F), KIRAN(Z130H)          #
 #                         TM2(64bit)
 ####################################################################
-%if "%{?profile}" == "mobile"
-
-%define tizen_privilege_engine                        CYNARA
-
-%define tizen_feature_account_support                 1
-%define tizen_feature_alarm_support                   1
-%define tizen_feature_app_control_settings_support    1
-%define tizen_feature_application_support             1
-%define tizen_feature_archive_support                 1
-%define tizen_feature_badge_support                   1
-%if 0%{?tizen_is_emulator}
-%define tizen_feature_bluetooth_support               0
-%else
-%define tizen_feature_bluetooth_support               1
-%endif
-%define tizen_feature_bookmark_support                1
-%define tizen_feature_calendar_support                1
-%define tizen_feature_contact_support                 1
-%define tizen_feature_content_support                 1
-%define tizen_feature_datacontrol_support             1
-%define tizen_feature_datasync_support                0
-%define tizen_feature_download_support                1
-%define tizen_feature_exif_support                    1
-%define tizen_feature_feedback_support                1
-%define tizen_feature_filesystem_support              1
 
-# FM radio feature
-%if 0%{?tizen_is_emulator}
-%define tizen_feature_fm_radio_support                1
-%else
-%if 0%{?tizen_is_arm64}
-%define tizen_feature_fm_radio_support                0
+%define tizen_mobile_privilege_engine                        CYNARA
+
+%define tizen_mobile_feature_account_support                 1
+%define tizen_mobile_feature_alarm_support                   1
+%define tizen_mobile_feature_app_control_settings_support    1
+%define tizen_mobile_feature_application_support             1
+%define tizen_mobile_feature_archive_support                 1
+%define tizen_mobile_feature_badge_support                   1
+%define tizen_mobile_feature_bluetooth_support               1
+%define tizen_mobile_feature_bookmark_support                1
+%define tizen_mobile_feature_calendar_support                1
+%define tizen_mobile_feature_contact_support                 1
+%define tizen_mobile_feature_content_support                 1
+%define tizen_mobile_feature_datacontrol_support             1
+%define tizen_mobile_feature_datasync_support                0
+%define tizen_mobile_feature_download_support                1
+%define tizen_mobile_feature_exif_support                    1
+%define tizen_mobile_feature_feedback_support                1
+%define tizen_mobile_feature_filesystem_support              1
+
+%ifarch aarch64
+%define tizen_mobile_feature_fm_radio_support                0
 %else
-%define tizen_feature_fm_radio_support                1
-%endif
+%define tizen_mobile_feature_fm_radio_support                1
 %endif
 
-%if 0%{?tizen_is_emulator}
-%define tizen_feature_ham_support                     1
-%else
-%define tizen_feature_ham_support                     0
-%endif
-%define tizen_feature_iotcon_support                  1
-%define tizen_feature_location_batch                  0
-%define tizen_feature_key_manager_support             1
-%define tizen_feature_media_controller_support        1
-%if 0%{?tizen_is_emulator}
-%define tizen_feature_media_key_support               0
-%else
-%define tizen_feature_media_key_support               1
-%endif
-%define tizen_feature_message_port_support            1
-%define tizen_feature_messaging_support               1
+%define tizen_mobile_feature_ham_support                     0
 
-%if 0%{?tizen_is_emulator}
-%define tizen_feature_nfc_emulation_support           0
-%define tizen_feature_nfc_support                     1
-%else
-%define tizen_feature_nfc_emulation_support           0
-%define tizen_feature_nfc_support                     0
-%endif
-%define tizen_feature_notification_support            1
-%define tizen_feature_package_support                 1
-%define tizen_feature_player_util_support             1
-%define tizen_feature_power_support                   1
-%define tizen_feature_preference_support              1
-%define tizen_feature_push_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_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_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_preference_support              1
+%define tizen_mobile_feature_push_support                    1
 
 # secure element feature
-%if 0%{?tizen_is_emulator}
-%define tizen_feature_se_support                      0
-%else
-%if 0%{?tizen_is_arm64}
-%define tizen_feature_se_support                      0
+%ifarch aarch64
+%define tizen_mobile_feature_se_support                      0
 %else
-%define tizen_feature_se_support                      1
-%endif
+%define tizen_mobile_feature_se_support                      1
 %endif
 
-%define tizen_feature_sensor_support                  1
-%define tizen_feature_sound_support                   1
-%define tizen_feature_system_info_support             1
-%define tizen_feature_system_setting_support          1
+%define tizen_mobile_feature_sensor_support                  1
+%define tizen_mobile_feature_sound_support                   1
+%define tizen_mobile_feature_system_info_support             1
+%define tizen_mobile_feature_system_setting_support          1
 
 # telephony feature
-%if 0%{?tizen_is_emulator}
-%define tizen_feature_telephony_support               1
-%else
-%if 0%{?tizen_is_arm64}
-%define tizen_feature_telephony_support               0
+%ifarch aarch64
+%define tizen_mobile_feature_telephony_support               0
+%define tizen_mobile_feature_callhistory_support             0
+%define tizen_mobile_feature_nbs_support                     0
 %else
-%define tizen_feature_telephony_support               1
-%endif
+%define tizen_mobile_feature_telephony_support               1
+%define tizen_mobile_feature_callhistory_support             1
+%define tizen_mobile_feature_nbs_support                     1
 %endif
 
-%define tizen_feature_time_support                    1
-%define tizen_feature_web_setting_support             1
-%define tizen_feature_widget_service_support          1
-%if 0%{?tizen_is_emulator}
-%define tizen_feature_wi_fi_support                   0
-%else
-%define tizen_feature_wi_fi_support                   1
-%endif
-%define tizen_feature_inputdevice_support             1
+%define tizen_mobile_feature_time_support                    1
+%define tizen_mobile_feature_web_setting_support             1
+%define tizen_mobile_feature_widget_service_support          1
 
-%if 0%{?tizen_feature_telephony_support}
-%define tizen_feature_callhistory_support             1
-%define tizen_feature_nbs_support                     1
-%else
-%define tizen_feature_callhistory_support             0
-%define tizen_feature_nbs_support                     0
-%endif
+%define tizen_mobile_feature_wi_fi_support                   1
 
-%define tizen_feature_tvinputdevice_support           0
+%define tizen_mobile_feature_inputdevice_support             1
 
-%endif # tizen_profile_mobile
+%define tizen_mobile_feature_tvinputdevice_support           0
+
+%define tizen_mobile_feature_voicecontrol_support            1
+%define tizen_mobile_feature_ppm_support                     1
 
 ####################################################################
-#       Wearable Profile :  B2 / TW1                      #
+#       Wearable Profile :  B2 / TW2                      #
 ####################################################################
-%if "%{?profile}" == "wearable"
 
-%define tizen_privilege_engine                        CYNARA
+%define tizen_wearable_privilege_engine                        CYNARA
 
 # Account API is optional in Tizen Wearable Profile.
-%define tizen_feature_account_support                 0
+%define tizen_wearable_feature_account_support                 1
 
-%define tizen_feature_alarm_support                   1
-%define tizen_feature_app_control_settings_support    1
-%define tizen_feature_application_support             1
+%define tizen_wearable_feature_alarm_support                   1
+%define tizen_wearable_feature_app_control_settings_support    1
+%define tizen_wearable_feature_application_support             1
 
 # Archive API is optional in Tizen Wearable Profile.
-%define tizen_feature_archive_support                 1
+%define tizen_wearable_feature_archive_support                 1
 
 # Badge API is mandatory in Tizen Wearable Profile.
-%define tizen_feature_badge_support                   1
+%define tizen_wearable_feature_badge_support                   1
 
-%if 0%{?tizen_is_emulator}
-%define tizen_feature_bluetooth_support               0
-%else
-%define tizen_feature_bluetooth_support               1
-%endif
+%define tizen_wearable_feature_bluetooth_support               1
 
 # Bookmark API is optional in Tizen Wearable Profile.
-%define tizen_feature_bookmark_support                0
+%define tizen_wearable_feature_bookmark_support                0
 
 # Calendar API is mandatory in Tizen Wearable Profile.
-%define tizen_feature_calendar_support                0
-%define tizen_feature_contact_support                 0
-%define tizen_feature_content_support                 1
-%define tizen_feature_datacontrol_support             1
-%define tizen_feature_datasync_support                0
-%define tizen_feature_download_support                1
-%define tizen_feature_exif_support                    1
-%define tizen_feature_feedback_support                1
-%define tizen_feature_filesystem_support              1
-%define tizen_feature_fm_radio_support                0
-%define tizen_feature_ham_support                     1
-%define tizen_feature_iotcon_support                  1
-%define tizen_feature_location_batch                  0
-%define tizen_feature_media_controller_support        1
+%define tizen_wearable_feature_calendar_support                1
+%define tizen_wearable_feature_contact_support                 1
+%define tizen_wearable_feature_content_support                 1
+%define tizen_wearable_feature_datacontrol_support             1
+%define tizen_wearable_feature_datasync_support                0
+%define tizen_wearable_feature_download_support                1
+%define tizen_wearable_feature_exif_support                    1
+%define tizen_wearable_feature_feedback_support                1
+%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_iotcon_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
-%if 0%{?tizen_is_emulator}
-%define tizen_feature_media_key_support               0
-%else
-%define tizen_feature_media_key_support               1
-%endif
-%define tizen_feature_key_manager_support             1
-%define tizen_feature_message_port_support            1
-%define tizen_feature_messaging_support               0
-%define tizen_feature_nfc_emulation_support           0
-%define tizen_feature_nfc_support                     1
-%define tizen_feature_notification_support            1
-%define tizen_feature_package_support                 1
-%define tizen_feature_player_util_support             1
-%define tizen_feature_power_support                   1
-%define tizen_feature_preference_support              1
-%define tizen_feature_push_support                    1
-%if 0%{?tizen_is_emulator}
-%define tizen_feature_se_support                      0
-%else
-%define tizen_feature_se_support                      1
-%endif
-%define tizen_feature_sensor_support                  1
-%define tizen_feature_sound_support                   1
-%define tizen_feature_system_info_support             1
-%define tizen_feature_system_setting_support          1
-%if 0%{?tizen_is_emulator}
-%define tizen_feature_telephony_support               1
-%else
-%define tizen_feature_telephony_support               0
-%endif
-%define tizen_feature_time_support                    1
-%define tizen_feature_web_setting_support             0
-%define tizen_feature_widget_service_support          1
-%define tizen_feature_wi_fi_support                   1
-%define tizen_feature_inputdevice_support             1
-%define tizen_feature_tvinputdevice_support           0
+%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_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_preference_support              1
+%define tizen_wearable_feature_push_support                    1
+%define tizen_wearable_feature_se_support                      1
+%define tizen_wearable_feature_sensor_support                  1
+%define tizen_wearable_feature_sound_support                   1
+%define tizen_wearable_feature_system_info_support             1
+%define tizen_wearable_feature_system_setting_support          1
 
 #- telephony related APIs
 # CallHistory API is optional in Tizen Wearable Profile.
 # NetworkBearerSelection API is optional in Tizen Wearable Profile.
-%if 0%{?tizen_feature_telephony_support}
-%define    tizen_feature_callhistory_support          1
-%define    tizen_feature_nbs_support                  1
-%else
-%define    tizen_feature_callhistory_support          0
-%define    tizen_feature_nbs_support                  0
-%endif
+%define tizen_wearable_feature_telephony_support               0
+%define tizen_wearable_feature_callhistory_support             0
+%define tizen_wearable_feature_nbs_support                     0
+
+%define tizen_wearable_feature_time_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_voicecontrol_support            1
+%define tizen_wearable_feature_ppm_support                     1
 
-%endif # tizen_profile_wearable
 
 ####################################################################
 #       TV Profile                                                 #
 ####################################################################
-%if "%{?profile}" == "tv"
 
-%define tizen_privilege_engine                        CYNARA
-
-%define tizen_feature_account_support                 0
-%define tizen_feature_alarm_support                   1
-%define tizen_feature_app_control_settings_support    0
-%define tizen_feature_application_support             1
-%define tizen_feature_archive_support                 1
-%define tizen_feature_badge_support                   0
-%define tizen_feature_bluetooth_support               0
-%define tizen_feature_bookmark_support                0
-%define tizen_feature_calendar_support                0
-%define tizen_feature_callhistory_support             0
-%define tizen_feature_contact_support                 0
-%define tizen_feature_content_support                 1
-%define tizen_feature_datacontrol_support             1
-%define tizen_feature_datasync_support                0
-%define tizen_feature_download_support                1
-%define tizen_feature_exif_support                    1
-%define tizen_feature_feedback_support                0
-%define tizen_feature_filesystem_support              1
-%define tizen_feature_fm_radio_support                0
-%define tizen_feature_ham_support                     0
-%define tizen_feature_iotcon_support                  1
-%define tizen_feature_key_manager_support             1
-%define tizen_feature_media_controller_support        0
-%define tizen_feature_media_key_support               1
-%define tizen_feature_message_port_support            1
-%define tizen_feature_messaging_support               0
-%define tizen_feature_nbs_support                     0
-%define tizen_feature_nfc_emulation_support           0
-%define tizen_feature_nfc_support                     0
-%define tizen_feature_notification_support            0
-%define tizen_feature_package_support                 1
-%define tizen_feature_player_util_support             0
-%define tizen_feature_power_support                   0
-%define tizen_feature_preference_support              0
-%define tizen_feature_push_support                    1
-%define tizen_feature_se_support                      0
-%define tizen_feature_sensor_support                  0
-%define tizen_feature_sound_support                   0
-%define tizen_feature_system_info_support             1
-%define tizen_feature_system_setting_support          0
-%define tizen_feature_telephony_support               0
-%define tizen_feature_time_support                    1
-%define tizen_feature_web_setting_support             1
-%define tizen_feature_widget_service_support          0
-%define tizen_feature_wi_fi_support                   1
-%define tizen_feature_inputdevice_support             0
-%define tizen_feature_tvinputdevice_support           1
-
-%endif # tizen_profile_tv
+%define tizen_tv_privilege_engine                        CYNARA
+
+%define tizen_tv_feature_account_support                 0
+%define tizen_tv_feature_alarm_support                   1
+%define tizen_tv_feature_app_control_settings_support    0
+%define tizen_tv_feature_application_support             1
+%define tizen_tv_feature_archive_support                 1
+%define tizen_tv_feature_badge_support                   0
+%define tizen_tv_feature_bluetooth_support               0
+%define tizen_tv_feature_bookmark_support                0
+%define tizen_tv_feature_calendar_support                0
+%define tizen_tv_feature_callhistory_support             0
+%define tizen_tv_feature_contact_support                 0
+%define tizen_tv_feature_content_support                 1
+%define tizen_tv_feature_datacontrol_support             1
+%define tizen_tv_feature_datasync_support                0
+%define tizen_tv_feature_download_support                1
+%define tizen_tv_feature_exif_support                    1
+%define tizen_tv_feature_feedback_support                0
+%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_iotcon_support                  1
+%define tizen_tv_feature_key_manager_support             1
+%define tizen_tv_feature_media_controller_support        0
+%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_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_preference_support              0
+%define tizen_tv_feature_push_support                    1
+%define tizen_tv_feature_se_support                      0
+%define tizen_tv_feature_sensor_support                  0
+%define tizen_tv_feature_sound_support                   0
+%define tizen_tv_feature_system_info_support             1
+%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
+
+# common, or "unified (undefined)"
+%define unified_build   1
+# GBM Product Build Optimization. Not for 4.0 Public Unified Build.
+%if "%{?profile}" == "tv" || "%{?profile}" == "mobile" || "%{?profile}" == "wearable" || "%{?profile}" == "ivi"
+%define unified_build  0
+%endif
+
+# GBM Product Build Optimization. Not for 4.0 Public Unified Build.
+%if "%{?profile}" == "tv" || "%{?profile}" == "mobile" || "%{?profile}" == "wearable" || "%{?profile}" == "common"
+%define tizen_privilege_engine                        %{expand:%tizen_%{?profile}_privilege_engine}
+
+%define tizen_feature_account_support                 %{expand:%tizen_%{?profile}_feature_account_support}
+%define tizen_feature_alarm_support                   %{expand:%tizen_%{?profile}_feature_alarm_support}
+%define tizen_feature_app_control_settings_support    %{expand:%tizen_%{?profile}_feature_app_control_settings_support}
+%define tizen_feature_application_support             %{expand:%tizen_%{?profile}_feature_application_support}
+%define tizen_feature_archive_support                 %{expand:%tizen_%{?profile}_feature_archive_support}
+%define tizen_feature_badge_support                   %{expand:%tizen_%{?profile}_feature_badge_support}
+%define tizen_feature_bluetooth_support               %{expand:%tizen_%{?profile}_feature_bluetooth_support}
+%define tizen_feature_bookmark_support                %{expand:%tizen_%{?profile}_feature_bookmark_support}
+%define tizen_feature_calendar_support                %{expand:%tizen_%{?profile}_feature_calendar_support}
+%define tizen_feature_contact_support                 %{expand:%tizen_%{?profile}_feature_contact_support}
+%define tizen_feature_content_support                 %{expand:%tizen_%{?profile}_feature_content_support}
+%define tizen_feature_datacontrol_support             %{expand:%tizen_%{?profile}_feature_datacontrol_support}
+%define tizen_feature_datasync_support                %{expand:%tizen_%{?profile}_feature_datasync_support}
+%define tizen_feature_download_support                %{expand:%tizen_%{?profile}_feature_download_support}
+%define tizen_feature_exif_support                    %{expand:%tizen_%{?profile}_feature_exif_support}
+%define tizen_feature_feedback_support                %{expand:%tizen_%{?profile}_feature_feedback_support}
+%define tizen_feature_filesystem_support              %{expand:%tizen_%{?profile}_feature_filesystem_support}
+%define tizen_feature_fm_radio_support                %{expand:%tizen_%{?profile}_feature_fm_radio_support}
+%define tizen_feature_ham_support                     %{expand:%tizen_%{?profile}_feature_ham_support}
+%define tizen_feature_iotcon_support                  %{expand:%tizen_%{?profile}_feature_iotcon_support}
+%define tizen_feature_location_batch                  %{expand:%tizen_%{?profile}_feature_location_batch}
+%define tizen_feature_key_manager_support             %{expand:%tizen_%{?profile}_feature_key_manager_support}
+%define tizen_feature_media_controller_support        %{expand:%tizen_%{?profile}_feature_media_controller_support}
+%define tizen_feature_media_key_support               %{expand:%tizen_%{?profile}_feature_media_key_support}
+%define tizen_feature_message_port_support            %{expand:%tizen_%{?profile}_feature_message_port_support}
+%define tizen_feature_messaging_support               %{expand:%tizen_%{?profile}_feature_messaging_support}
+%define tizen_feature_nfc_emulation_support           %{expand:%tizen_%{?profile}_feature_nfc_emulation_support}
+%define tizen_feature_nfc_support                     %{expand:%tizen_%{?profile}_feature_nfc_support}
+%define tizen_feature_notification_support            %{expand:%tizen_%{?profile}_feature_notification_support}
+%define tizen_feature_package_support                 %{expand:%tizen_%{?profile}_feature_package_support}
+%define tizen_feature_player_util_support             %{expand:%tizen_%{?profile}_feature_player_util_support}
+%define tizen_feature_power_support                   %{expand:%tizen_%{?profile}_feature_power_support}
+%define tizen_feature_preference_support              %{expand:%tizen_%{?profile}_feature_preference_support}
+%define tizen_feature_push_support                    %{expand:%tizen_%{?profile}_feature_push_support}
+%define tizen_feature_se_support                      %{expand:%tizen_%{?profile}_feature_se_support}
+%define tizen_feature_sensor_support                  %{expand:%tizen_%{?profile}_feature_sensor_support}
+%define tizen_feature_sound_support                   %{expand:%tizen_%{?profile}_feature_sound_support}
+%define tizen_feature_system_info_support             %{expand:%tizen_%{?profile}_feature_system_info_support}
+%define tizen_feature_system_setting_support          %{expand:%tizen_%{?profile}_feature_system_setting_support}
+%define tizen_feature_telephony_support               %{expand:%tizen_%{?profile}_feature_telephony_support}
+%define tizen_feature_time_support                    %{expand:%tizen_%{?profile}_feature_time_support}
+%define tizen_feature_web_setting_support             %{expand:%tizen_%{?profile}_feature_web_setting_support}
+%define tizen_feature_widget_service_support          %{expand:%tizen_%{?profile}_feature_widget_service_support}
+%define tizen_feature_wi_fi_support                   %{expand:%tizen_%{?profile}_feature_wi_fi_support}
+%define tizen_feature_inputdevice_support             %{expand:%tizen_%{?profile}_feature_inputdevice_support}
+%define tizen_feature_callhistory_support             %{expand:%tizen_%{?profile}_feature_callhistory_support}
+%define tizen_feature_nbs_support                     %{expand:%tizen_%{?profile}_feature_nbs_support}
+%define tizen_feature_tvinputdevice_support           %{expand:%tizen_%{?profile}_feature_tvinputdevice_support}
+%define tizen_feature_voicecontrol_support            %{expand:%tizen_%{?profile}_feature_voicecontrol_support}
+%define tizen_feature_ppm_support                     %{expand:%tizen_%{?profile}_feature_ppm_support}
+%endif
 
 BuildRequires: pkgconfig(security-privilege-manager)
 BuildRequires: ninja
@@ -396,7 +389,7 @@ BuildRequires: pkgconfig(capi-network-bluetooth)
 BuildRequires: pkgconfig(capi-network-wifi-manager)
 BuildRequires: pkgconfig(tapi)
 BuildRequires: pkgconfig(libpcrecpp)
-BuildRequires: pkgconfig(capi-appfw-application)
+BuildRequires: pkgconfig(capi-appfw-app-common)
 BuildRequires: pkgconfig(capi-appfw-app-manager)
 BuildRequires: pkgconfig(capi-appfw-package-manager)
 BuildRequires: pkgconfig(capi-content-media-content)
@@ -417,69 +410,82 @@ BuildRequires: pkgconfig(wayland-client)
 BuildRequires: pkgconfig(security-privilege-checker)
 %endif
 
-%if "%{?tizen_privilege_engine}" == "CYNARA"
+%if "%{?tizen_privilege_engine}" == "CYNARA" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(cynara-client)
 BuildRequires: pkgconfig(libsmack)
 %endif
 
-%if 0%{?tizen_feature_account_support}
+%if "%{?tizen_feature_account_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(accounts-svc)
 %endif
 
-%if 0%{?tizen_feature_alarm_support}
+%if "%{?tizen_feature_alarm_support}" == "1" || "%{?unified_build}" == "1"
+BuildRequires: pkgconfig(capi-appfw-app-control)
+BuildRequires: pkgconfig(capi-appfw-application)
 BuildRequires: pkgconfig(capi-appfw-alarm)
 BuildRequires: pkgconfig(alarm-service)
 %endif
 
-%if 0%{?tizen_feature_bookmark_support}
+%if "%{?tizen_feature_application_support}" == "1" || "%{?unified_build}" == "1"
+BuildRequires: pkgconfig(capi-appfw-app-control)
+BuildRequires: pkgconfig(capi-appfw-event)
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "mobile" || "%{?profile}" == "wearable"
+BuildRequires: pkgconfig(capi-context)
+%endif
+
+%endif
+
+%if "%{?tizen_feature_bluetooth_support}" == "1" || "%{?unified_build}" == "1"
+BuildRequires: pkgconfig(capi-appfw-app-control)
+%endif
+
+%if "%{?tizen_feature_bookmark_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(capi-web-bookmark)
 BuildRequires: pkgconfig(bookmark-adaptor)
 %endif
 
-%if 0%{?tizen_feature_datacontrol_support}
+%if "%{?tizen_feature_datacontrol_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(capi-data-control)
 %endif
 
-%if 0%{?tizen_feature_download_support}
+%if "%{?tizen_feature_download_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(capi-web-url-download)
 %endif
 
-%if 0%{?tizen_feature_ham_support}
+%if "%{?tizen_feature_ham_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(motion)
 BuildRequires: pkgconfig(capi-system-sensor)
 BuildRequires: pkgconfig(capi-location-manager)
 BuildRequires: pkgconfig(sensor)
 %endif
 
-%if 0%{?tizen_feature_iotcon_support}
+%if "%{?tizen_feature_iotcon_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(iotcon)
 %endif
 
-%if 0%{?tizen_feature_player_util_support}
+%if "%{?tizen_feature_player_util_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(chromium-efl)
 %endif
 
-%if 0%{?tizen_feature_power_support}
-BuildRequires: pkgconfig(deviced)
-%endif
-
-%if 0%{?tizen_feature_power_support}
+%if "%{?tizen_feature_power_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(capi-appfw-application)
 %endif
 
-%if 0%{?tizen_feature_push_support}
+%if "%{?tizen_feature_push_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(push)
+BuildRequires: pkgconfig(capi-appfw-app-control)
 %endif
 
-%if 0%{?tizen_feature_key_manager_support}
+%if "%{?tizen_feature_key_manager_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(key-manager)
 %endif
 
-%if 0%{?tizen_feature_media_controller_support}
+%if "%{?tizen_feature_media_controller_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(capi-media-controller)
 %endif
 
-%if 0%{?tizen_feature_messaging_support}
+%if "%{?tizen_feature_messaging_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires:  pkgconfig(ecore-file)
 BuildRequires:  pkgconfig(email-service)
 BuildRequires:  pkgconfig(msg-service)
@@ -487,69 +493,154 @@ BuildRequires:  pkgconfig(db-util)
 BuildRequires:  pkgconfig(dbus-glib-1)
 %endif
 
-%if 0%{?tizen_feature_badge_support}
+%if "%{?tizen_feature_badge_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires:  pkgconfig(badge)
 %endif
 
-%if 0%{?tizen_feature_calendar_support}
+%if "%{?tizen_feature_calendar_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires:  pkgconfig(calendar-service2)
 %endif
 
-%if 0%{?tizen_feature_contact_support}
+%if "%{?tizen_feature_contact_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires:  pkgconfig(contacts-service2)
 %endif
 
-%if 0%{?tizen_feature_callhistory_support}
+%if "%{?tizen_feature_callhistory_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires:  pkgconfig(contacts-service2)
 %endif
 
-%if 0%{?tizen_feature_exif_support}
+%if "%{?tizen_feature_exif_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires:  pkgconfig(libexif)
 %endif
 
-%if 0%{?tizen_feature_nfc_support}
+%if "%{?tizen_feature_nfc_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires:  pkgconfig(capi-network-nfc)
+BuildRequires:  pkgconfig(capi-appfw-app-control)
 %endif
 
-%if 0%{?tizen_feature_fm_radio_support}
+%if "%{?tizen_feature_fm_radio_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(capi-media-radio)
 %endif
 
-%if 0%{?tizen_feature_feedback_support}
+%if "%{?tizen_feature_feedback_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(feedback)
 %endif
 
-%if 0%{?tizen_feature_se_support}
+%if "%{?tizen_feature_se_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires:  pkgconfig(capi-network-smartcard)
 %endif
 
-%if 0%{?tizen_feature_message_port_support}
+%if "%{?tizen_feature_message_port_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(capi-message-port)
 %endif
 
-%if 0%{?tizen_feature_notification_support}
+%if "%{?tizen_feature_notification_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(notification)
+BuildRequires: pkgconfig(capi-appfw-app-control)
+%endif
+
+%if "%{?tizen_feature_preference_support}" == "1" || "%{?unified_build}" == "1"
+BuildRequires: pkgconfig(capi-appfw-preference)
 %endif
 
-%if 0%{?tizen_feature_sound_support}
+%if "%{?tizen_feature_sound_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires:  pkgconfig(capi-media-sound-manager)
 %endif
 
-%if 0%{?tizen_feature_sensor_support}
+%if "%{?tizen_feature_sensor_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(capi-system-sensor)
 %endif
 
-%if 0%{?tizen_feature_media_key_support}
+%if "%{?tizen_feature_media_key_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires:  pkgconfig(capi-system-media-key)
 %endif
 
-%if 0%{?tizen_feature_widget_service_support}
+%if "%{?tizen_feature_widget_service_support}" == "1" || "%{?unified_build}" == "1"
 BuildRequires: pkgconfig(widget_service)
 %endif
 
+%if "%{?tizen_feature_voicecontrol_support}" == "1" || "%{?unified_build}" == "1"
+BuildRequires: pkgconfig(voice-control)
+%endif
+
+%if "%{?tizen_feature_ppm_support}" == "1" || "%{?unified_build}" == "1"
+BuildRequires: pkgconfig(capi-privacy-privilege-manager)
+%endif
+
+Requires:      %{name}-compat = %{version}-%{release}
+%if "%{?unified_build}" == "1"
+Recommends:    %{name}-profile_common = %{version}-%{release}
+%endif
+
 %description
 Tizen Web APIs implemented.
 
+%package profile_common
+Summary:       webapi-plugin binaries for common profile
+Provides:      %{name}-compat = %{version}-%{release}
+Conflicts:     %{name}-profile_mobile
+Conflicts:     %{name}-profile_wearable
+Conflicts:     %{name}-profile_tv
+Conflicts:     %{name}-profile_ivi
+%description profile_common
+Tizen Web API implementation binaries for Tizen common profile.
+
+%package profile_mobile
+Summary:       webapi-plugin binaries for mobile profile
+Provides:      %{name}-compat = %{version}-%{release}
+Conflicts:     %{name}-profile_common
+Conflicts:     %{name}-profile_wearable
+Conflicts:     %{name}-profile_tv
+Conflicts:     %{name}-profile_ivi
+%description profile_mobile
+Tizen Web API implementation binaries for Tizen mobile profile.
+
+%ifarch %{ix86} x86_64
+%package mobile-extension-emulator
+Summary:       webapi-plugin binaries for mobile emulator
+Requires:      %{name}-profile_mobile = %{version}-%{release}
+%description mobile-extension-emulator
+Tizen Web API implementation binaries for Tizen mobile emulator.
+%endif
+
+%package profile_wearable
+Summary:       webapi-plugin binaries for wearable profile
+Provides:      %{name}-compat = %{version}-%{release}
+Conflicts:     %{name}-profile_mobile
+Conflicts:     %{name}-profile_common
+Conflicts:     %{name}-profile_tv
+Conflicts:     %{name}-profile_ivi
+%description profile_wearable
+Tizen Web API implementation binaries for Tizen wearable profile.
+
+%ifarch %{ix86} x86_64
+%package wearable-extension-emulator
+Summary:       webapi-plugin binaries for wearable emulator
+Requires:      %{name}-profile_wearable = %{version}-%{release}
+%description wearable-extension-emulator
+Tizen Web API implementation binaries for Tizen wearable emulator.
+%endif
+
+%package profile_tv
+Summary:       webapi-plugin binaries for tv profile
+Provides:      %{name}-compat = %{version}-%{release}
+Conflicts:     %{name}-profile_mobile
+Conflicts:     %{name}-profile_wearable
+Conflicts:     %{name}-profile_common
+Conflicts:     %{name}-profile_ivi
+%description profile_tv
+Tizen Web API implementation binaries for Tizen tv profile.
+
+%package profile_ivi
+Summary:       webapi-plugin binaries for ivi profile
+Provides:      %{name}-compat = %{version}-%{release}
+Conflicts:     %{name}-profile_mobile
+Conflicts:     %{name}-profile_wearable
+Conflicts:     %{name}-profile_tv
+Conflicts:     %{name}-profile_common
+%description profile_ivi
+Tizen Web API implementation binaries for Tizen ivi profile.
+
 %package devel
 Summary:    webapi-plugins development headers
 Group:      Development/Libraries
@@ -564,75 +655,572 @@ webapi-plugins development headers
 %build
 
 export GYP_GENERATORS='ninja'
-GYP_OPTIONS="--depth=. -Dtizen=1 -Dextension_build_type=Debug -Dextension_host_os=%{profile} -Dprivilege_engine=%{tizen_privilege_engine}"
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "mobile"
+# MOBILE
+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}"
+GYP_OPTIONS="$GYP_OPTIONS -Dcrosswalk_extensions_path=%{crosswalk_extensions_path}"
+
+# feature flags
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_account_support=%{?tizen_mobile_feature_account_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_alarm_support=%{?tizen_mobile_feature_alarm_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_app_control_settings_support=%{?tizen_mobile_feature_app_control_settings_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_application_support=%{?tizen_mobile_feature_application_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_archive_support=%{?tizen_mobile_feature_archive_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_badge_support=%{?tizen_mobile_feature_badge_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bluetooth_support=%{?tizen_mobile_feature_bluetooth_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bookmark_support=%{?tizen_mobile_feature_bookmark_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_calendar_support=%{?tizen_mobile_feature_calendar_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_callhistory_support=%{?tizen_mobile_feature_callhistory_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_contact_support=%{?tizen_mobile_feature_contact_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_content_support=%{?tizen_mobile_feature_content_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datacontrol_support=%{?tizen_mobile_feature_datacontrol_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datasync_support=%{?tizen_mobile_feature_datasync_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_download_support=%{?tizen_mobile_feature_download_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_exif_support=%{?tizen_mobile_feature_exif_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_feedback_support=%{?tizen_mobile_feature_feedback_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_filesystem_support=%{?tizen_mobile_feature_filesystem_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_fm_radio_support=%{?tizen_mobile_feature_fm_radio_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ham_support=%{?tizen_mobile_feature_ham_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_iotcon_support=%{?tizen_mobile_feature_iotcon_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_location_batch=%{?tizen_mobile_feature_location_batch}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_key_manager_support=%{?tizen_mobile_feature_key_manager_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_controller_support=%{?tizen_mobile_feature_media_controller_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_key_support=%{?tizen_mobile_feature_media_key_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_message_port_support=%{?tizen_mobile_feature_message_port_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_messaging_support=%{?tizen_mobile_feature_messaging_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nbs_support=%{?tizen_mobile_feature_nbs_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_emulation_support=%{?tizen_mobile_feature_nfc_emulation_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_support=%{?tizen_mobile_feature_nfc_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_notification_support=%{?tizen_mobile_feature_notification_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_package_support=%{?tizen_mobile_feature_package_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_player_util_support=%{?tizen_mobile_feature_player_util_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_power_support=%{?tizen_mobile_feature_power_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_preference_support=%{?tizen_mobile_feature_preference_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_push_support=%{?tizen_mobile_feature_push_support}"
+#GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sap_support=%{?tizen_mobile_feature_sap_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sensor_support=%{?tizen_mobile_feature_sensor_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_se_support=%{?tizen_mobile_feature_se_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sound_support=%{?tizen_mobile_feature_sound_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_info_support=%{?tizen_mobile_feature_system_info_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_setting_support=%{?tizen_mobile_feature_system_setting_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_telephony_support=%{?tizen_mobile_feature_telephony_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_time_support=%{?tizen_mobile_feature_time_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_inputdevice_support=%{?tizen_mobile_feature_inputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_mobile_feature_web_setting_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_mobile_feature_widget_service_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_mobile_feature_wi_fi_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_mobile_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_voicecontrol_support=%{?tizen_mobile_feature_voicecontrol_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ppm_support=%{?tizen_mobile_feature_ppm_support}"
+
+./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
+
+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
+
+# FM radio feature
+%define tizen_mobile_feature_fm_radio_support                1
+
+%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
+
+# secure element feature
+%define tizen_mobile_feature_se_support                      0
+
+# 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_wi_fi_support                   0
+
+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}"
+GYP_OPTIONS="$GYP_OPTIONS -Dcrosswalk_extensions_path=%{crosswalk_extensions_path}"
+
+# feature flags
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_account_support=%{?tizen_mobile_feature_account_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_alarm_support=%{?tizen_mobile_feature_alarm_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_app_control_settings_support=%{?tizen_mobile_feature_app_control_settings_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_application_support=%{?tizen_mobile_feature_application_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_archive_support=%{?tizen_mobile_feature_archive_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_badge_support=%{?tizen_mobile_feature_badge_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bluetooth_support=%{?tizen_mobile_feature_bluetooth_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bookmark_support=%{?tizen_mobile_feature_bookmark_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_calendar_support=%{?tizen_mobile_feature_calendar_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_callhistory_support=%{?tizen_mobile_feature_callhistory_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_contact_support=%{?tizen_mobile_feature_contact_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_content_support=%{?tizen_mobile_feature_content_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datacontrol_support=%{?tizen_mobile_feature_datacontrol_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datasync_support=%{?tizen_mobile_feature_datasync_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_download_support=%{?tizen_mobile_feature_download_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_exif_support=%{?tizen_mobile_feature_exif_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_feedback_support=%{?tizen_mobile_feature_feedback_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_filesystem_support=%{?tizen_mobile_feature_filesystem_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_fm_radio_support=%{?tizen_mobile_feature_fm_radio_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ham_support=%{?tizen_mobile_feature_ham_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_iotcon_support=%{?tizen_mobile_feature_iotcon_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_location_batch=%{?tizen_mobile_feature_location_batch}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_key_manager_support=%{?tizen_mobile_feature_key_manager_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_controller_support=%{?tizen_mobile_feature_media_controller_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_key_support=%{?tizen_mobile_feature_media_key_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_message_port_support=%{?tizen_mobile_feature_message_port_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_messaging_support=%{?tizen_mobile_feature_messaging_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nbs_support=%{?tizen_mobile_feature_nbs_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_emulation_support=%{?tizen_mobile_feature_nfc_emulation_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_support=%{?tizen_mobile_feature_nfc_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_notification_support=%{?tizen_mobile_feature_notification_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_package_support=%{?tizen_mobile_feature_package_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_player_util_support=%{?tizen_mobile_feature_player_util_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_power_support=%{?tizen_mobile_feature_power_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_preference_support=%{?tizen_mobile_feature_preference_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_push_support=%{?tizen_mobile_feature_push_support}"
+#GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sap_support=%{?tizen_mobile_feature_sap_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sensor_support=%{?tizen_mobile_feature_sensor_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_se_support=%{?tizen_mobile_feature_se_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sound_support=%{?tizen_mobile_feature_sound_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_info_support=%{?tizen_mobile_feature_system_info_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_setting_support=%{?tizen_mobile_feature_system_setting_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_telephony_support=%{?tizen_mobile_feature_telephony_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_time_support=%{?tizen_mobile_feature_time_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_inputdevice_support=%{?tizen_mobile_feature_inputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_mobile_feature_web_setting_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_mobile_feature_widget_service_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_mobile_feature_wi_fi_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_mobile_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_voicecontrol_support=%{?tizen_mobile_feature_voicecontrol_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ppm_support=%{?tizen_mobile_feature_ppm_support}"
+
+./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
+
+ninja -C out/Default %{?_smp_mflags}
+pushd out
+mv Default bin_mobile_emulator
+%if "%{?profile}" == "mobile"
+ln -sf bin_mobile_emulator Default
+%endif
+popd
+%endif # mobile-extension-emulator
+%endif # MOBILE
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "wearable"
+# WEARABLE
+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}"
+GYP_OPTIONS="$GYP_OPTIONS -Dcrosswalk_extensions_path=%{crosswalk_extensions_path}"
+
+# feature flags
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_account_support=%{?tizen_wearable_feature_account_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_alarm_support=%{?tizen_wearable_feature_alarm_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_app_control_settings_support=%{?tizen_wearable_feature_app_control_settings_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_application_support=%{?tizen_wearable_feature_application_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_archive_support=%{?tizen_wearable_feature_archive_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_badge_support=%{?tizen_wearable_feature_badge_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bluetooth_support=%{?tizen_wearable_feature_bluetooth_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bookmark_support=%{?tizen_wearable_feature_bookmark_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_calendar_support=%{?tizen_wearable_feature_calendar_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_callhistory_support=%{?tizen_wearable_feature_callhistory_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_contact_support=%{?tizen_wearable_feature_contact_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_content_support=%{?tizen_wearable_feature_content_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datacontrol_support=%{?tizen_wearable_feature_datacontrol_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datasync_support=%{?tizen_wearable_feature_datasync_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_download_support=%{?tizen_wearable_feature_download_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_exif_support=%{?tizen_wearable_feature_exif_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_feedback_support=%{?tizen_wearable_feature_feedback_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_filesystem_support=%{?tizen_wearable_feature_filesystem_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_fm_radio_support=%{?tizen_wearable_feature_fm_radio_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ham_support=%{?tizen_wearable_feature_ham_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_iotcon_support=%{?tizen_wearable_feature_iotcon_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_location_batch=%{?tizen_wearable_feature_location_batch}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_key_manager_support=%{?tizen_wearable_feature_key_manager_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_controller_support=%{?tizen_wearable_feature_media_controller_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_key_support=%{?tizen_wearable_feature_media_key_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_message_port_support=%{?tizen_wearable_feature_message_port_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_messaging_support=%{?tizen_wearable_feature_messaging_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nbs_support=%{?tizen_wearable_feature_nbs_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_emulation_support=%{?tizen_wearable_feature_nfc_emulation_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_support=%{?tizen_wearable_feature_nfc_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_notification_support=%{?tizen_wearable_feature_notification_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_package_support=%{?tizen_wearable_feature_package_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_player_util_support=%{?tizen_wearable_feature_player_util_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_power_support=%{?tizen_wearable_feature_power_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_preference_support=%{?tizen_wearable_feature_preference_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_push_support=%{?tizen_wearable_feature_push_support}"
+#GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sap_support=%{?tizen_wearable_feature_sap_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sensor_support=%{?tizen_wearable_feature_sensor_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_se_support=%{?tizen_wearable_feature_se_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sound_support=%{?tizen_wearable_feature_sound_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_info_support=%{?tizen_wearable_feature_system_info_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_setting_support=%{?tizen_wearable_feature_system_setting_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_telephony_support=%{?tizen_wearable_feature_telephony_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_time_support=%{?tizen_wearable_feature_time_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_inputdevice_support=%{?tizen_wearable_feature_inputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_wearable_feature_web_setting_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_wearable_feature_widget_service_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_wearable_feature_wi_fi_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_wearable_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_voicecontrol_support=%{?tizen_wearable_feature_voicecontrol_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ppm_support=%{?tizen_wearable_feature_ppm_support}"
+
+./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
+
+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
+
+# 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
+
+#- 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
+
+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}"
 GYP_OPTIONS="$GYP_OPTIONS -Dcrosswalk_extensions_path=%{crosswalk_extensions_path}"
 
 # feature flags
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_is_emulator=%{?tizen_is_emulator}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_account_support=%{?tizen_feature_account_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_alarm_support=%{?tizen_feature_alarm_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_app_control_settings_support=%{?tizen_feature_app_control_settings_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_application_support=%{?tizen_feature_application_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_archive_support=%{?tizen_feature_archive_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_badge_support=%{?tizen_feature_badge_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bluetooth_support=%{?tizen_feature_bluetooth_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bookmark_support=%{?tizen_feature_bookmark_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_calendar_support=%{?tizen_feature_calendar_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_callhistory_support=%{?tizen_feature_callhistory_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_contact_support=%{?tizen_feature_contact_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_content_support=%{?tizen_feature_content_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datacontrol_support=%{?tizen_feature_datacontrol_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datasync_support=%{?tizen_feature_datasync_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_download_support=%{?tizen_feature_download_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_exif_support=%{?tizen_feature_exif_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_feedback_support=%{?tizen_feature_feedback_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_filesystem_support=%{?tizen_feature_filesystem_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_fm_radio_support=%{?tizen_feature_fm_radio_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ham_support=%{?tizen_feature_ham_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_iotcon_support=%{?tizen_feature_iotcon_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_location_batch=%{?tizen_feature_location_batch}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_key_manager_support=%{?tizen_feature_key_manager_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_controller_support=%{?tizen_feature_media_controller_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_key_support=%{?tizen_feature_media_key_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_message_port_support=%{?tizen_feature_message_port_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_messaging_support=%{?tizen_feature_messaging_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nbs_support=%{?tizen_feature_nbs_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_emulation_support=%{?tizen_feature_nfc_emulation_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_support=%{?tizen_feature_nfc_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_notification_support=%{?tizen_feature_notification_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_package_support=%{?tizen_feature_package_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_player_util_support=%{?tizen_feature_player_util_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_power_support=%{?tizen_feature_power_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_preference_support=%{?tizen_feature_preference_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_push_support=%{?tizen_feature_push_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sap_support=%{?tizen_feature_sap_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sensor_support=%{?tizen_feature_sensor_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_se_support=%{?tizen_feature_se_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sound_support=%{?tizen_feature_sound_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_info_support=%{?tizen_feature_system_info_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_setting_support=%{?tizen_feature_system_setting_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_telephony_support=%{?tizen_feature_telephony_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_time_support=%{?tizen_feature_time_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_inputdevice_support=%{?tizen_feature_inputdevice_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_feature_web_setting_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_feature_widget_service_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_feature_wi_fi_support}"
-GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_account_support=%{?tizen_wearable_feature_account_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_alarm_support=%{?tizen_wearable_feature_alarm_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_app_control_settings_support=%{?tizen_wearable_feature_app_control_settings_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_application_support=%{?tizen_wearable_feature_application_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_archive_support=%{?tizen_wearable_feature_archive_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_badge_support=%{?tizen_wearable_feature_badge_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bluetooth_support=%{?tizen_wearable_feature_bluetooth_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bookmark_support=%{?tizen_wearable_feature_bookmark_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_calendar_support=%{?tizen_wearable_feature_calendar_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_callhistory_support=%{?tizen_wearable_feature_callhistory_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_contact_support=%{?tizen_wearable_feature_contact_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_content_support=%{?tizen_wearable_feature_content_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datacontrol_support=%{?tizen_wearable_feature_datacontrol_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datasync_support=%{?tizen_wearable_feature_datasync_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_download_support=%{?tizen_wearable_feature_download_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_exif_support=%{?tizen_wearable_feature_exif_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_feedback_support=%{?tizen_wearable_feature_feedback_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_filesystem_support=%{?tizen_wearable_feature_filesystem_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_fm_radio_support=%{?tizen_wearable_feature_fm_radio_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ham_support=%{?tizen_wearable_feature_ham_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_iotcon_support=%{?tizen_wearable_feature_iotcon_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_location_batch=%{?tizen_wearable_feature_location_batch}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_key_manager_support=%{?tizen_wearable_feature_key_manager_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_controller_support=%{?tizen_wearable_feature_media_controller_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_key_support=%{?tizen_wearable_feature_media_key_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_message_port_support=%{?tizen_wearable_feature_message_port_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_messaging_support=%{?tizen_wearable_feature_messaging_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nbs_support=%{?tizen_wearable_feature_nbs_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_emulation_support=%{?tizen_wearable_feature_nfc_emulation_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_support=%{?tizen_wearable_feature_nfc_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_notification_support=%{?tizen_wearable_feature_notification_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_package_support=%{?tizen_wearable_feature_package_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_player_util_support=%{?tizen_wearable_feature_player_util_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_power_support=%{?tizen_wearable_feature_power_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_preference_support=%{?tizen_wearable_feature_preference_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_push_support=%{?tizen_wearable_feature_push_support}"
+#GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sap_support=%{?tizen_wearable_feature_sap_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sensor_support=%{?tizen_wearable_feature_sensor_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_se_support=%{?tizen_wearable_feature_se_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sound_support=%{?tizen_wearable_feature_sound_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_info_support=%{?tizen_wearable_feature_system_info_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_setting_support=%{?tizen_wearable_feature_system_setting_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_telephony_support=%{?tizen_wearable_feature_telephony_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_time_support=%{?tizen_wearable_feature_time_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_inputdevice_support=%{?tizen_wearable_feature_inputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_wearable_feature_web_setting_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_wearable_feature_widget_service_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_wearable_feature_wi_fi_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_wearable_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_voicecontrol_support=%{?tizen_wearable_feature_voicecontrol_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ppm_support=%{?tizen_wearable_feature_ppm_support}"
 
 ./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
 
 ninja -C out/Default %{?_smp_mflags}
+pushd out
+mv Default bin_wearable_emulator
+%if "%{?profile}" == "wearable"
+ln -sf bin_wearable_emulator Default
+%endif
+popd
+%endif # wearable-extension-emulator
+%endif # WEARABLE
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "tv"
+# TV
+GYP_OPTIONS="--depth=. -Dtizen=1 -Dextension_build_type=Debug -Dextension_host_os=tv -Dprivilege_engine=%{tizen_tv_privilege_engine}"
+GYP_OPTIONS="$GYP_OPTIONS -Ddisplay_type=%{display_type}"
+GYP_OPTIONS="$GYP_OPTIONS -Dcrosswalk_extensions_path=%{crosswalk_extensions_path}"
+
+# feature flags
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_account_support=%{?tizen_tv_feature_account_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_alarm_support=%{?tizen_tv_feature_alarm_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_app_control_settings_support=%{?tizen_tv_feature_app_control_settings_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_application_support=%{?tizen_tv_feature_application_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_archive_support=%{?tizen_tv_feature_archive_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_badge_support=%{?tizen_tv_feature_badge_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bluetooth_support=%{?tizen_tv_feature_bluetooth_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bookmark_support=%{?tizen_tv_feature_bookmark_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_calendar_support=%{?tizen_tv_feature_calendar_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_callhistory_support=%{?tizen_tv_feature_callhistory_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_contact_support=%{?tizen_tv_feature_contact_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_content_support=%{?tizen_tv_feature_content_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datacontrol_support=%{?tizen_tv_feature_datacontrol_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datasync_support=%{?tizen_tv_feature_datasync_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_download_support=%{?tizen_tv_feature_download_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_exif_support=%{?tizen_tv_feature_exif_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_feedback_support=%{?tizen_tv_feature_feedback_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_filesystem_support=%{?tizen_tv_feature_filesystem_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_fm_radio_support=%{?tizen_tv_feature_fm_radio_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ham_support=%{?tizen_tv_feature_ham_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_iotcon_support=%{?tizen_tv_feature_iotcon_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_location_batch=%{?tizen_tv_feature_location_batch}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_key_manager_support=%{?tizen_tv_feature_key_manager_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_controller_support=%{?tizen_tv_feature_media_controller_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_key_support=%{?tizen_tv_feature_media_key_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_message_port_support=%{?tizen_tv_feature_message_port_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_messaging_support=%{?tizen_tv_feature_messaging_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nbs_support=%{?tizen_tv_feature_nbs_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_emulation_support=%{?tizen_tv_feature_nfc_emulation_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_support=%{?tizen_tv_feature_nfc_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_notification_support=%{?tizen_tv_feature_notification_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_package_support=%{?tizen_tv_feature_package_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_player_util_support=%{?tizen_tv_feature_player_util_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_power_support=%{?tizen_tv_feature_power_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_preference_support=%{?tizen_tv_feature_preference_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_push_support=%{?tizen_tv_feature_push_support}"
+#GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sap_support=%{?tizen_tv_feature_sap_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sensor_support=%{?tizen_tv_feature_sensor_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_se_support=%{?tizen_tv_feature_se_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sound_support=%{?tizen_tv_feature_sound_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_info_support=%{?tizen_tv_feature_system_info_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_setting_support=%{?tizen_tv_feature_system_setting_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_telephony_support=%{?tizen_tv_feature_telephony_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_time_support=%{?tizen_tv_feature_time_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_inputdevice_support=%{?tizen_tv_feature_inputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_tv_feature_web_setting_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_tv_feature_widget_service_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_tv_feature_wi_fi_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_tv_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_voicecontrol_support=%{?tizen_tv_feature_voicecontrol_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ppm_support=%{?tizen_tv_feature_ppm_support}"
+
+./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
+
+ninja -C out/Default %{?_smp_mflags}
+pushd out
+mv Default bin_tv
+%if "%{?profile}" == "tv"
+ln -sf bin_tv Default
+%endif
+popd
+
+%endif # TV
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "common" || "%{?profile}" == "ivi"
+
+# UNIFIED / COMMON or IVI
+GYP_OPTIONS="--depth=. -Dtizen=1 -Dextension_build_type=Debug -Dextension_host_os=common -Dprivilege_engine=%{tizen_common_privilege_engine}"
+
+GYP_OPTIONS="$GYP_OPTIONS -Ddisplay_type=%{display_type}"
+GYP_OPTIONS="$GYP_OPTIONS -Dcrosswalk_extensions_path=%{crosswalk_extensions_path}"
+
+# feature flags
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_account_support=%{?tizen_common_feature_account_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_alarm_support=%{?tizen_common_feature_alarm_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_app_control_settings_support=%{?tizen_common_feature_app_control_settings_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_application_support=%{?tizen_common_feature_application_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_archive_support=%{?tizen_common_feature_archive_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_badge_support=%{?tizen_common_feature_badge_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bluetooth_support=%{?tizen_common_feature_bluetooth_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_bookmark_support=%{?tizen_common_feature_bookmark_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_calendar_support=%{?tizen_common_feature_calendar_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_callhistory_support=%{?tizen_common_feature_callhistory_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_contact_support=%{?tizen_common_feature_contact_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_content_support=%{?tizen_common_feature_content_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datacontrol_support=%{?tizen_common_feature_datacontrol_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_datasync_support=%{?tizen_common_feature_datasync_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_download_support=%{?tizen_common_feature_download_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_exif_support=%{?tizen_common_feature_exif_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_feedback_support=%{?tizen_common_feature_feedback_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_filesystem_support=%{?tizen_common_feature_filesystem_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_fm_radio_support=%{?tizen_common_feature_fm_radio_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ham_support=%{?tizen_common_feature_ham_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_iotcon_support=%{?tizen_common_feature_iotcon_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_location_batch=%{?tizen_common_feature_location_batch}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_key_manager_support=%{?tizen_common_feature_key_manager_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_controller_support=%{?tizen_common_feature_media_controller_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_media_key_support=%{?tizen_common_feature_media_key_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_message_port_support=%{?tizen_common_feature_message_port_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_messaging_support=%{?tizen_common_feature_messaging_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nbs_support=%{?tizen_common_feature_nbs_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_emulation_support=%{?tizen_common_feature_nfc_emulation_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_nfc_support=%{?tizen_common_feature_nfc_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_notification_support=%{?tizen_common_feature_notification_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_package_support=%{?tizen_common_feature_package_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_player_util_support=%{?tizen_common_feature_player_util_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_power_support=%{?tizen_common_feature_power_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_preference_support=%{?tizen_common_feature_preference_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_push_support=%{?tizen_common_feature_push_support}"
+#GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sap_support=%{?tizen_common_feature_sap_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sensor_support=%{?tizen_common_feature_sensor_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_se_support=%{?tizen_common_feature_se_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_sound_support=%{?tizen_common_feature_sound_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_info_support=%{?tizen_common_feature_system_info_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_system_setting_support=%{?tizen_common_feature_system_setting_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_telephony_support=%{?tizen_common_feature_telephony_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_time_support=%{?tizen_common_feature_time_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_inputdevice_support=%{?tizen_common_feature_inputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_common_feature_web_setting_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_common_feature_widget_service_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_common_feature_wi_fi_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_common_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_voicecontrol_support=%{?tizen_common_feature_voicecontrol_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_ppm_support=%{?tizen_common_feature_ppm_support}"
+
+./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
+
+%if "%{?unified_build}" == "1"
+# UNIFIED
+ninja -C out/Default %{?_smp_mflags}
+pushd out
+mv Default bin_common
+ln -sf bin_common Default
+
+# IVI does not have independent configurations, yet.
+# Copying the whole result in order to support ivi subpacakge
+cp -R bin_common bin_ivi
+
+popd
+%else # UNIFIED
+# COMMON or IVI
+ninja -C out/Default %{?_smp_mflags}
+pushd out
+mv Default bin_%{?profile}
+ln -sf bin_%{?profile} Default
+popd
+%endif # COMMON or IVI
+%endif # UNIFIED / COMMON or IVI
 
 %install
-mkdir -p %{buildroot}/usr/share/license
-cp LICENSE %{buildroot}/usr/share/license/%{name}
-cat LICENSE.BSD-3-Clause >> %{buildroot}/usr/share/license/%{name}
-cat LICENSE.MIT >> %{buildroot}/usr/share/license/%{name}
 
 # Extensions.
 mkdir -p %{buildroot}%{crosswalk_extensions_path}
-install -p -m 644 out/Default/libtizen*.so %{buildroot}%{crosswalk_extensions_path}
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "common"
+mkdir -p %{buildroot}%{crosswalk_extensions_path}/common
+install -p -m 644 out/bin_common/libtizen*.so %{buildroot}%{crosswalk_extensions_path}/common
+# execute desc_gentool
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%{buildroot}%{crosswalk_extensions_path}/common out/Default/desc_gentool \
+       %{crosswalk_extensions_path}/common \
+       %{buildroot}%{crosswalk_extensions_path}/common > plugins.json
+
+# temporary plugins description for lazy loading
+install -p -m 644 plugins.json %{buildroot}%{crosswalk_extensions_path}/common/plugins.json
+%endif
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "mobile"
+mkdir -p %{buildroot}%{crosswalk_extensions_path}/mobile
+install -p -m 644 out/bin_mobile/libtizen*.so %{buildroot}%{crosswalk_extensions_path}/mobile
+# execute desc_gentool
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%{buildroot}%{crosswalk_extensions_path}/mobile out/Default/desc_gentool \
+       %{crosswalk_extensions_path}/mobile \
+       %{buildroot}%{crosswalk_extensions_path}/mobile > plugins.json
+
+# temporary plugins description for lazy loading
+install -p -m 644 plugins.json %{buildroot}%{crosswalk_extensions_path}/mobile/plugins.json
+
+# mobile-extension-emulator
+%ifarch %{ix86} x86_64
+mkdir -p %{buildroot}%{crosswalk_extensions_path}/mobile_emulator
+install -p -m 644 out/bin_mobile_emulator/libtizen*.so %{buildroot}%{crosswalk_extensions_path}/mobile_emulator
+# execute desc_gentool
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%{buildroot}%{crosswalk_extensions_path}/mobile_emulator out/Default/desc_gentool \
+       %{crosswalk_extensions_path}/mobile_emulator \
+       %{buildroot}%{crosswalk_extensions_path}/mobile_emulator > plugins.json
+
+# temporary plugins description for lazy loading
+install -p -m 644 plugins.json %{buildroot}%{crosswalk_extensions_path}/mobile_emulator/plugins.json
+%endif // mobile-extension-emulator
+
+%endif // mobile
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "wearable"
+mkdir -p %{buildroot}%{crosswalk_extensions_path}/wearable
+install -p -m 644 out/bin_wearable/libtizen*.so %{buildroot}%{crosswalk_extensions_path}/wearable
+# execute desc_gentool
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%{buildroot}%{crosswalk_extensions_path}/wearable out/Default/desc_gentool \
+       %{crosswalk_extensions_path}/wearable \
+       %{buildroot}%{crosswalk_extensions_path}/wearable > plugins.json
+
+# temporary plugins description for lazy loading
+install -p -m 644 plugins.json %{buildroot}%{crosswalk_extensions_path}/wearable/plugins.json
+
+# wearable-extension-emulator
+%ifarch %{ix86} x86_64
+mkdir -p %{buildroot}%{crosswalk_extensions_path}/wearable_emulator
+install -p -m 644 out/bin_wearable_emulator/libtizen*.so %{buildroot}%{crosswalk_extensions_path}/wearable_emulator
+# execute desc_gentool
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%{buildroot}%{crosswalk_extensions_path}/wearable_emulator out/Default/desc_gentool \
+       %{crosswalk_extensions_path}/wearable_emulator \
+       %{buildroot}%{crosswalk_extensions_path}/wearable_emulator > plugins.json
+
+# temporary plugins description for lazy loading
+install -p -m 644 plugins.json %{buildroot}%{crosswalk_extensions_path}/wearable_emulator/plugins.json
+%endif // wearable-extension-emulator
+
+%endif // wearable
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "tv"
+mkdir -p %{buildroot}%{crosswalk_extensions_path}/tv
+install -p -m 644 out/bin_tv/libtizen*.so %{buildroot}%{crosswalk_extensions_path}/tv
+# execute desc_gentool
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%{buildroot}%{crosswalk_extensions_path}/tv out/Default/desc_gentool \
+       %{crosswalk_extensions_path}/tv \
+       %{buildroot}%{crosswalk_extensions_path}/tv > plugins.json
+
+# temporary plugins description for lazy loading
+install -p -m 644 plugins.json %{buildroot}%{crosswalk_extensions_path}/tv/plugins.json
+%endif
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "ivi"
+mkdir -p %{buildroot}%{crosswalk_extensions_path}/ivi
+install -p -m 644 out/bin_ivi/libtizen*.so %{buildroot}%{crosswalk_extensions_path}/ivi
+# execute desc_gentool
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%{buildroot}%{crosswalk_extensions_path}/ivi out/Default/desc_gentool \
+       %{crosswalk_extensions_path}/ivi \
+       %{buildroot}%{crosswalk_extensions_path}/ivi > plugins.json
+
+# temporary plugins description for lazy loading
+install -p -m 644 plugins.json %{buildroot}%{crosswalk_extensions_path}/ivi/plugins.json
+%endif
 
 # devel files
 mkdir -p %{buildroot}%{_libdir}/pkgconfig
@@ -653,20 +1241,139 @@ cp -a tools/gyp %{buildroot}%{_includedir}/%{name}/tools/gyp
 cp -a tools/slimit %{buildroot}%{_includedir}/%{name}/tools/slimit
 cp -a out/Default/desc_gentool %{buildroot}%{_includedir}/%{name}/tools/desc_gentool
 
-# execute desc_gentool
-LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%{buildroot}%{crosswalk_extensions_path} out/Default/desc_gentool \
-       %{crosswalk_extensions_path} \
-       %{buildroot}%{crosswalk_extensions_path} > plugins.json
+%files
+%manifest webapi-plugins.manifest
+%license LICENSE
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "common"
+%post profile_common
+ln -sf %{crosswalk_extensions_path}/common/* %{crosswalk_extensions_path}
+%preun profile_common
+# This is an un-installation.
+if [ "$1" == "0" ]; then
+  rm %{crosswalk_extensions_path}/libtizen*.so
+  rm %{crosswalk_extensions_path}/plugins.json
+fi
+%files profile_common
+%dir %{crosswalk_extensions_path}/common/
+%{crosswalk_extensions_path}/common/libtizen*.so
+%{crosswalk_extensions_path}/common/plugins.json
+%manifest webapi-plugins.manifest
+%endif
 
-# temporary plugins description for lazy loading
-install -p -m 644 plugins.json %{buildroot}%{crosswalk_extensions_path}/plugins.json
+%if "%{?unified_build}" == "1" || "%{?profile}" == "mobile"
+%post profile_mobile
+ln -sf %{crosswalk_extensions_path}/mobile/* %{crosswalk_extensions_path}
+%preun profile_mobile
+# This is an un-installation.
+if [ "$1" == "0" ]; then
+  if [ -n "$(ls %{crosswalk_extensions_path}/ | grep libtizen*.so)" ]; then
+    rm %{crosswalk_extensions_path}/libtizen*.so
+  fi
+  if [ -f %{crosswalk_extensions_path}/plugins.json ]; then
+    rm %{crosswalk_extensions_path}/plugins.json
+  fi
+fi
+%files profile_mobile
+%dir %{crosswalk_extensions_path}/mobile/
+%{crosswalk_extensions_path}/mobile/libtizen*.so
+%{crosswalk_extensions_path}/mobile/plugins.json
+%manifest webapi-plugins.manifest
+
+# mobile-extension-emulator
+%ifarch %{ix86} x86_64
+%post mobile-extension-emulator
+ln -sf %{crosswalk_extensions_path}/mobile_emulator/* %{crosswalk_extensions_path}
+%preun mobile-extension-emulator
+# This is an un-installation.
+if [ "$1" == "0" ]; then
+  if [ -n "$(ls %{crosswalk_extensions_path}/ | grep libtizen*.so)" ]; then
+    rm %{crosswalk_extensions_path}/libtizen*.so
+  fi
+  if [ -f %{crosswalk_extensions_path}/plugins.json ]; then
+    rm %{crosswalk_extensions_path}/plugins.json
+  fi
+fi
+%files mobile-extension-emulator
+%dir %{crosswalk_extensions_path}/mobile_emulator/
+%{crosswalk_extensions_path}/mobile_emulator/libtizen*.so
+%{crosswalk_extensions_path}/mobile_emulator/plugins.json
+%manifest webapi-plugins.manifest
+%endif // mobile-extension-emulator
+%endif // mobile
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "wearable"
+%post profile_wearable
+ln -sf %{crosswalk_extensions_path}/wearable/* %{crosswalk_extensions_path}
+%preun profile_wearable
+# This is an un-installation.
+if [ "$1" == "0" ]; then
+  if [ -n "$(ls %{crosswalk_extensions_path}/ | grep libtizen*.so)" ]; then
+    rm %{crosswalk_extensions_path}/libtizen*.so
+  fi
+  if [ -f %{crosswalk_extensions_path}/plugins.json ]; then
+    rm %{crosswalk_extensions_path}/plugins.json
+  fi
+fi
+%files profile_wearable
+%dir %{crosswalk_extensions_path}/wearable/
+%{crosswalk_extensions_path}/wearable/libtizen*.so
+%{crosswalk_extensions_path}/wearable/plugins.json
+%manifest webapi-plugins.manifest
 
+# wearable-extension-emulator
+%ifarch %{ix86} x86_64
+%post wearable-extension-emulator
+ln -sf %{crosswalk_extensions_path}/wearable_emulator/* %{crosswalk_extensions_path}
+%preun wearable-extension-emulator
+# This is an un-installation.
+if [ "$1" == "0" ]; then
+  if [ -n "$(ls %{crosswalk_extensions_path}/ | grep libtizen*.so)" ]; then
+    rm %{crosswalk_extensions_path}/libtizen*.so
+  fi
+  if [ -f %{crosswalk_extensions_path}/plugins.json ]; then
+    rm %{crosswalk_extensions_path}/plugins.json
+  fi
+fi
+%files wearable-extension-emulator
+%dir %{crosswalk_extensions_path}/wearable_emulator/
+%{crosswalk_extensions_path}/wearable_emulator/libtizen*.so
+%{crosswalk_extensions_path}/wearable_emulator/plugins.json
+%manifest webapi-plugins.manifest
+%endif // wearable-extension-emulator
+%endif // wearable
+
+%if "%{?unified_build}" == "1" || "%{?profile}" == "tv"
+%post profile_tv
+ln -sf %{crosswalk_extensions_path}/tv/* %{crosswalk_extensions_path}
+%preun profile_tv
+# This is an un-installation.
+if [ "$1" == "0" ]; then
+  rm %{crosswalk_extensions_path}/libtizen*.so
+  rm %{crosswalk_extensions_path}/plugins.json
+fi
+%files profile_tv
+%dir %{crosswalk_extensions_path}/tv/
+%{crosswalk_extensions_path}/tv/libtizen*.so
+%{crosswalk_extensions_path}/tv/plugins.json
+%manifest webapi-plugins.manifest
+%endif
 
-%files
-%{crosswalk_extensions_path}/libtizen*.so
-%{crosswalk_extensions_path}/plugins.json
-%{_datadir}/license/%{name}
+%if "%{?unified_build}" == "1" || "%{?profile}" == "ivi"
+%post profile_ivi
+ln -sf %{crosswalk_extensions_path}/ivi/* %{crosswalk_extensions_path}
+%preun profile_ivi
+# This is an un-installation.
+if [ "$1" == "0" ]; then
+  rm %{crosswalk_extensions_path}/libtizen*.so
+  rm %{crosswalk_extensions_path}/plugins.json
+fi
+%files profile_ivi
+%dir %{crosswalk_extensions_path}/ivi/
+%{crosswalk_extensions_path}/ivi/libtizen*.so
+%{crosswalk_extensions_path}/ivi/plugins.json
 %manifest webapi-plugins.manifest
+%endif
 
 %files devel
 %{_includedir}/*
index dc1135a..6a5739e 100644 (file)
           'variables': {
             'packages': [
               'capi-appfw-alarm',
+              'capi-appfw-app-control',
+              'capi-appfw-application',
             ]
           },
         }],
+        ['extension_host_os == "mobile"', {
+            'dependencies': [
+              '../notification/notification.gyp:tizen_notification',
+            ],
+        }],
+        ['extension_host_os == "wearable"', {
+            'dependencies': [
+             '../notification/notification.gyp:tizen_notification',
+            ],
+        }]
       ],
     },
   ],
index e7692a4..eb66886 100755 (executable)
@@ -21,6 +21,8 @@ var privUtils_ = xwalk.utils;
 
 var native = new xwalk.utils.NativeManager(extension);
 
+var isAlarmAbsolutePeriodDeprecated = true;
+
 var AlarmManager = function() {
     Object.defineProperties(this, {
         PERIOD_MINUTE: { value: 60, writable: false, enumerable: true },
@@ -66,6 +68,20 @@ function UpdateInternalData_(internal, data) {
     }
 }
 
+var LogManager = function() {
+    this.enableLog = true;
+};
+
+LogManager.prototype.allow = function() {
+    this.enableLog = true;
+};
+
+LogManager.prototype.disallow = function() {
+    this.enableLog = false;
+};
+
+var _warningLogs = new LogManager();
+
 //class AlarmManager ////////////////////////////////////////////////////
 AlarmManager.prototype.add = function() {
     var args = AV.validateMethod(arguments, [
@@ -117,6 +133,49 @@ AlarmManager.prototype.add = function() {
     }
 };
 
+AlarmManager.prototype.addAlarmNotification = function() {
+    var args = AV.validateMethod(arguments, [
+        {
+            name: 'alarm',
+            type: AV.Types.PLATFORM_OBJECT,
+            values: [tizen.AlarmRelative, tizen.AlarmAbsolute]
+        },
+        {
+            name: 'notification',
+            type: AV.Types.PLATFORM_OBJECT,
+            values: [tizen.StatusNotification, tizen.UserNotification]
+        }
+    ]);
+
+    var type = null,
+        milliseconds = 0;
+    if (args.alarm instanceof tizen.AlarmRelative) {
+        type = 'AlarmRelative';
+    } else if (args.alarm instanceof tizen.AlarmAbsolute) {
+        type = 'AlarmAbsolute';
+        milliseconds = args.alarm.date.getTime();
+    }
+
+    var callArgs = {};
+    callArgs.alarm = args.alarm;
+    callArgs.type = type;
+    callArgs.notification = args.notification;
+    callArgs.milliseconds = Converter.toString(milliseconds);
+    callArgs.isPeriodSet = !T.isNullOrUndefined(args.alarm.period);
+
+    //add marker for UserNotification implementation
+    callArgs.newImpl = callArgs.notification instanceof tizen.UserNotification;
+
+    var result = native.callSync('AlarmManager_addAlarmNotification', callArgs);
+    if (native.isFailure(result)) {
+        throw native.getErrorObject(result);
+    } else {
+        _edit.allow();
+        UpdateInternalData_(args.alarm, native.getResultObject(result));
+        _edit.disallow();
+    }
+};
+
 AlarmManager.prototype.remove = function() {
     var args = AV.validateMethod(arguments, [
         {
@@ -154,8 +213,11 @@ AlarmManager.prototype.get = function() {
         throw native.getErrorObject(result);
     } else {
         result = native.getResultObject(result);
+
+        var alarm;
+        _warningLogs.disallow();
         if ('AlarmRelative' === result.type) {
-            return new tizen.AlarmRelative(
+            alarm = new tizen.AlarmRelative(
                 result.delay,
                 result.period,
                 InternalData_(result)
@@ -170,8 +232,69 @@ AlarmManager.prototype.get = function() {
                 result.sec
             );
 
-            return new tizen.AlarmAbsolute(date, result.second, InternalData_(result));
+            alarm = new tizen.AlarmAbsolute(date, result.second, InternalData_(result));
         }
+        _warningLogs.allow();
+        return alarm;
+    }
+};
+
+function _prepareAppControl(noti) {
+    if (!noti || !noti.actions || !noti.actions.appControl) {
+        privUtils_.log('Do nothing - appControl is NOT present');
+        return;
+    }
+    if (!T.isNullOrUndefined(noti.actions.appControl.operation)) {
+        noti.actions.appControl = new tizen.ApplicationControl(
+            noti.actions.appControl.operation,
+            noti.actions.appControl.uri,
+            noti.actions.appControl.mime,
+            noti.actions.appControl.category,
+            noti.actions.appControl.data,
+            noti.actions.appControl.launchMode
+        );
+    }
+}
+
+function _prepareDetailInfo(noti) {
+    if (!noti || !noti.textContents || !noti.textContents.detailInfo) {
+        console.log('Do nothing - detailInfo is NOT present');
+        return;
+    }
+    var detailInfo = noti.textContents.detailInfo;
+    if (T.isArray(detailInfo)) {
+        var _d = [];
+        for (var i = 0; i < detailInfo.length; ++i) {
+            _d.push(
+                new tizen.NotificationDetailInfo(
+                    detailInfo[i].mainText,
+                    detailInfo[i].subText || null
+                )
+            );
+        }
+        noti.textContents.detailInfo = _d;
+    }
+}
+
+AlarmManager.prototype.getAlarmNotification = function() {
+    var args = AV.validateMethod(arguments, [
+        {
+            name: 'id',
+            type: AV.Types.STRING
+        }
+    ]);
+
+    var result = native.callSync('AlarmManager_getAlarmNotification', {
+        id: Number(args.id)
+    });
+
+    if (native.isFailure(result)) {
+        throw native.getErrorObject(result);
+    } else {
+        var noti = native.getResultObject(result);
+        _prepareAppControl(noti);
+        _prepareDetailInfo(noti);
+        return new tizen.UserNotification(noti.userType, noti.title, noti);
     }
 };
 
@@ -183,6 +306,7 @@ AlarmManager.prototype.getAll = function() {
     } else {
         var data = native.getResultObject(result);
         var md = [];
+        _warningLogs.disallow();
         data.forEach(function(i) {
             if ('AlarmRelative' === i.type) {
                 md.push(new tizen.AlarmRelative(i.delay, i.period, InternalData_(i)));
@@ -191,6 +315,7 @@ AlarmManager.prototype.getAll = function() {
                 md.push(new tizen.AlarmAbsolute(date, i.second, InternalData_(i)));
             }
         });
+        _warningLogs.allow();
         return md;
     }
 };
@@ -318,6 +443,13 @@ tizen.AlarmAbsolute = function(date, second, internal) {
             } else {
                 if (!T.isNullOrUndefined(second)) {
                     m_period = Converter.toLong(second);
+                    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.'
+                        );
+                    }
                 }
             }
         }
@@ -341,9 +473,24 @@ tizen.AlarmAbsolute = function(date, second, internal) {
         },
         period: {
             get: function() {
+                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.'
+                    );
+                }
                 return m_period;
             },
             set: function(v) {
+                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.'
+                    );
+                }
+
                 if (_edit.canEdit && v) {
                     m_period = Converter.toLong(v.period);
                 }
@@ -386,5 +533,45 @@ tizen.AlarmAbsolute.prototype.getNextScheduledDate = function() {
     }
 };
 
+// Singleton to check on which profile plugins are executed
+var ProfileAlarm = (function() {
+    var m_profile = null;
+    function ProfileAlarm() {
+        if (m_profile == null) {
+            m_profile = privUtils_.checkProfile();
+        }
+        Object.defineProperties(this, {
+            profile: {
+                get: function() {
+                    return m_profile;
+                },
+                set: function() {},
+                enumerable: true
+            }
+        });
+    }
+
+    var instance;
+    return {
+        getInstance: function() {
+            if (instance == null) {
+                instance = new ProfileAlarm();
+                // Hide the constructor so the returned objected can't be new'd...
+                instance.constructor = null;
+            }
+            return instance;
+        }
+    };
+})();
+
+var _profile = ProfileAlarm.getInstance().profile;
+
+// Notifications feature are available on mobile and wearable profile
+if (_profile != 'mobile' && _profile != 'wearable') {
+    delete AlarmManager.prototype.addAlarmNotification;
+    delete AlarmManager.prototype.getAlarmNotification;
+    isAlarmAbsolutePeriodDeprecated = false;
+}
+
 //exports //////////////////////////////////////////////////////////////
 exports = new AlarmManager();
index 1be9f9b..ad0f4af 100644 (file)
@@ -40,6 +40,14 @@ AlarmInstance::AlarmInstance() {
   // AlarmAbsolute
   RegisterSyncHandler("AlarmAbsolute_getNextScheduledDate",
                       std::bind(&AlarmManager::GetNextScheduledDate, &manager_, _1, _2));
+
+// Block of code related to Notification
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+  RegisterSyncHandler("AlarmManager_addAlarmNotification",
+                      std::bind(&AlarmManager::AddAlarmNotification, &manager_, _1, _2));
+  RegisterSyncHandler("AlarmManager_getAlarmNotification",
+                      std::bind(&AlarmManager::GetAlarmNotification, &manager_, _1, _2));
+#endif
 }
 
 AlarmInstance::~AlarmInstance() {
index 7a23181..d0d83f4 100644 (file)
 #include <app_alarm.h>
 #include <app_control_internal.h>
 
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+#include <notification_internal.h>
+#endif
+
 #include "common/converter.h"
 #include "common/logger.h"
 #include "common/scope_exit.h"
 #include "alarm_instance.h"
 #include "alarm_utils.h"
 
+#include "notification/common_notification.h"
+#include "notification/status_notification.h"
+#include "notification/user_notification.h"
+
 using namespace common;
 using namespace common::tools;
 
@@ -38,6 +46,7 @@ namespace alarm {
 namespace {
 const int kDateSize = 22;  //"yyy mm dd hh mm ss dd" e.g 115 11 28 11 25 50 -1
 const std::string kPrivilegeAlarm = "http://tizen.org/privilege/alarm";
+const std::string kPrivilegeNotification = "http://tizen.org/privilege/notification";
 
 const std::string kAlarmRelative = "AlarmRelative";
 const std::string kAlarmAbsolute = "AlarmAbsolute";
@@ -54,14 +63,6 @@ const char* kAlarmTypeValueAbsolute = "ABSOLUTE";
 const char* kAlarmTypeValueRelative = "RELATIVE";
 
 const char* kAlarmRelativeDelayKey = "RELATIVE_DELAY";
-
-const char* kSundayShort = "SU";
-const char* kMondayShort = "MO";
-const char* kTuesdayShort = "TU";
-const char* kWednesdayShort = "WE";
-const char* kThuesdayShort = "TH";
-const char* kFridayShort = "FR";
-const char* kSaturdayShort = "SA";
 }
 
 AlarmManager::AlarmManager() {
@@ -142,14 +143,16 @@ void AlarmManager::Add(const picojson::value& args, picojson::object& out) {
     }
 
     std::string delay_str = std::to_string(delay);
-    int ret = app_control_add_extra_data(app_control, kAlarmRelativeDelayKey, delay_str.c_str());
-    if (APP_CONTROL_ERROR_NONE != ret) {
+    int ret_app =
+        app_control_add_extra_data(app_control, kAlarmRelativeDelayKey, delay_str.c_str());
+    if (APP_CONTROL_ERROR_NONE != ret_app) {
       LogAndReportError(
           PlatformResult(ErrorCode::UNKNOWN_ERR, "Fail to add data from app_control."), &out,
-          ("Fail to add data from app_control: %d (%s)", ret, get_error_message(ret)));
+          ("Fail to add data from app_control: %d (%s)", ret_app, get_error_message(ret_app)));
       return;
     }
 
+    int ret = ALARM_ERROR_NONE;
     if (!isPeriodSet) {
       ret = alarm_schedule_once_after_delay(app_control, delay, &alarm_id);
     } else {
@@ -220,30 +223,12 @@ void AlarmManager::Add(const picojson::value& args, picojson::object& out) {
                !(it_daysOfTheWeek->second.get<picojson::array>()).empty()) {
       app_control_add_extra_data(app_control, kAlarmAbsoluteRecurrenceTypeKey,
                                  kAlarmAbsoluteReccurrenceTypeByDayValue);
-      picojson::array days_of_the_week = it_daysOfTheWeek->second.get<picojson::array>();
+      const picojson::array& days_of_the_week = it_daysOfTheWeek->second.get<picojson::array>();
       int repeat_value = 0;
-      for (auto iter = days_of_the_week.begin(); iter != days_of_the_week.end(); ++iter) {
-        auto day = (*iter).get<std::string>();
-        if (kSundayShort == day) {
-          repeat_value |= ALARM_WEEK_FLAG_SUNDAY;
-        } else if (kMondayShort == day) {
-          repeat_value |= ALARM_WEEK_FLAG_MONDAY;
-        } else if (kTuesdayShort == day) {
-          repeat_value |= ALARM_WEEK_FLAG_TUESDAY;
-        } else if (kWednesdayShort == day) {
-          repeat_value |= ALARM_WEEK_FLAG_WEDNESDAY;
-        } else if (kThuesdayShort == day) {
-          repeat_value |= ALARM_WEEK_FLAG_THURSDAY;
-        } else if (kFridayShort == day) {
-          repeat_value |= ALARM_WEEK_FLAG_FRIDAY;
-        } else if (kSaturdayShort == day) {
-          repeat_value |= ALARM_WEEK_FLAG_SATURDAY;
-        } else {
-          LogAndReportError(
-              PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Invalid days of the week value."),
-              &out);
-          return;
-        }
+      PlatformResult result = util::ArrayDaysToMask(days_of_the_week, &repeat_value);
+      if (!result) {
+        LogAndReportError(PlatformResult(result.error_code(), result.message()), &out);
+        return;
       }
       ret = alarm_schedule_with_recurrence_week_flag(app_control, &start_date, repeat_value,
                                                      &alarm_id);
@@ -265,6 +250,230 @@ void AlarmManager::Add(const picojson::value& args, picojson::object& out) {
   ReportSuccess(result, out);
 }
 
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+void AlarmManager::AddAlarmNotification(const picojson::value& args, picojson::object& out) {
+  using namespace extension::notification;
+  ScopeLogger();
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeAlarm, &out);
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeNotification, &out);
+
+  if (!args.contains("alarm") || !args.contains("notification")) {
+    LogAndReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."),
+                      &out);
+    return;
+  }
+
+  const picojson::object& alarm = args.get("alarm").get<picojson::object>();
+
+  std::string alarm_type;
+  if (args.contains("type")) {
+    alarm_type = args.get("type").get<std::string>();
+  }
+
+  notification_h notification_handle = nullptr;
+  app_control_h app_control = nullptr;
+
+  SCOPE_EXIT {
+    notification_free(notification_handle);
+    app_control_destroy(app_control);
+  };
+
+  using namespace std::placeholders;
+  GetHandleFromJsonFun impl{};
+  if (args.contains("newImpl") && args.get("newImpl").is<bool>() &&
+      args.get("newImpl").get<bool>()) {
+    LoggerD("New implementation");
+    impl = std::bind(&UserNotification::GetNotiHandleFromJson, _1, _2, _3);
+  } else {
+    LoggerW("Deprecated object used");
+    impl = std::bind(&StatusNotification::GetNotiHandleFromJson, _1, _2, _3);
+  }
+
+  PlatformResult platform_result = impl(args.get("notification"), false, &notification_handle);
+  if (!platform_result) {
+    LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, platform_result.message().c_str()),
+                      &out);
+  }
+  platform_result = CommonNotification::GetAppControl(notification_handle, &app_control);
+
+  if (!platform_result) {
+    LogAndReportError(
+        PlatformResult(platform_result.error_code(), platform_result.message().c_str()), &out);
+  }
+
+  int alarm_id = 0;
+  int ret = 0;
+
+  if (kAlarmRelative == alarm_type) {
+    ret = app_control_add_extra_data(app_control, kAlarmKeyType, kAlarmTypeValueRelative);
+    if (ret != APP_CONTROL_ERROR_NONE) {
+      LogAndReportError(
+          PlatformResult(ErrorCode::ABORT_ERR, "Fail to add data from app_control."), &out,
+          ("Fail to add data from app_control: %d (%s)", ret, get_error_message(ret)));
+      return;
+    }
+
+    const auto it_period = alarm.find("period");
+    const auto it_delay = alarm.find("delay");
+
+    if (alarm.end() == it_delay || alarm.end() == it_period || !it_delay->second.is<double>()) {
+      LogAndReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."),
+                        &out);
+      return;
+    }
+
+    int delay = static_cast<int>(it_delay->second.get<double>());
+
+    std::string delay_str = std::to_string(delay);
+    ret = app_control_add_extra_data(app_control, kAlarmRelativeDelayKey, delay_str.c_str());
+    if (APP_CONTROL_ERROR_NONE != ret) {
+      LogAndReportError(
+          PlatformResult(ErrorCode::ABORT_ERR, "Fail to add data from app_control."), &out,
+          ("Fail to add data from app_control: %d (%s)", ret, get_error_message(ret)));
+      return;
+    }
+
+    platform_result = CommonNotification::SetAppControl(notification_handle, app_control);
+
+    if (!platform_result) {
+      LogAndReportError(
+          PlatformResult(platform_result.error_code(), platform_result.message().c_str()), &out);
+    }
+
+    int period = 0;
+    if (it_period->second.is<double>()) {
+      period = static_cast<int>(it_period->second.get<double>());
+    }
+
+    bool isPeriodSet = false;
+    if (args.contains("isPeriodSet")) {
+      isPeriodSet = args.get("isPeriodSet").get<bool>();
+    }
+
+    if (!isPeriodSet) {
+      ret = alarm_schedule_noti_once_after_delay(notification_handle, delay, &alarm_id);
+    } else {
+      ret = alarm_schedule_noti_after_delay(notification_handle, delay, period, &alarm_id);
+    }
+  } else {
+    if (alarm.find("period")->second.is<double>()) {
+      LogAndReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR,
+                                       "AlarmAbsolute constructed by deprecated constructor."),
+                        &out);
+      return;
+    }
+
+    ret = app_control_add_extra_data(app_control, kAlarmKeyType, kAlarmTypeValueAbsolute);
+    if (APP_CONTROL_ERROR_NONE != ret) {
+      LogAndReportError(
+          PlatformResult(ErrorCode::ABORT_ERR, "Fail to add data from app_control."), &out,
+          ("Fail to add data from app_control: %d (%s)", ret, get_error_message(ret)));
+      return;
+    }
+
+    const auto it_daysOfTheWeek = alarm.find("daysOfTheWeek");
+    long long int milliseconds = 0;
+
+    if (args.contains("milliseconds")) {
+      milliseconds = strtoll(args.get("milliseconds").get<std::string>().c_str(), nullptr, 10);
+    }
+
+    time_t second = milliseconds / 1000;
+    struct tm start_date = {0};
+
+    tzset();
+    if (nullptr == localtime_r(&second, &start_date)) {
+      LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Invalid date."), &out);
+      return;
+    }
+
+    mktime(&start_date);
+
+    char str_date[kDateSize];
+
+    snprintf(str_date, sizeof(str_date), "%d %d %d %d %d %d %d", start_date.tm_year,
+             start_date.tm_mon, start_date.tm_mday, start_date.tm_hour, start_date.tm_min,
+             start_date.tm_sec, start_date.tm_isdst);
+
+    ret = app_control_add_extra_data(app_control, kAlarmAbsoluteDateKey, str_date);
+    if (APP_CONTROL_ERROR_NONE != ret) {
+      LogAndReportError(
+          PlatformResult(ErrorCode::ABORT_ERR, "Fail to add data from app_control."), &out,
+          ("Fail to add data from app_control: %d (%s)", ret, get_error_message(ret)));
+      return;
+    }
+
+    if (alarm.end() != it_daysOfTheWeek && it_daysOfTheWeek->second.is<picojson::array>() &&
+        !(it_daysOfTheWeek->second.get<picojson::array>()).empty()) {
+      app_control_add_extra_data(app_control, kAlarmAbsoluteRecurrenceTypeKey,
+                                 kAlarmAbsoluteReccurrenceTypeByDayValue);
+
+      const picojson::array& days_of_the_week = it_daysOfTheWeek->second.get<picojson::array>();
+      int repeat_value = 0;
+      util::ArrayDaysToMask(days_of_the_week, &repeat_value);
+
+      platform_result = CommonNotification::SetAppControl(notification_handle, app_control);
+      if (!platform_result) {
+        LogAndReportError(
+            PlatformResult(platform_result.error_code(), platform_result.message().c_str()), &out);
+      }
+
+      ret = alarm_schedule_noti_with_recurrence_week_flag(notification_handle, &start_date,
+                                                          repeat_value, &alarm_id);
+    } else {
+      ret = app_control_add_extra_data(app_control, kAlarmAbsoluteRecurrenceTypeKey,
+                                       kAlarmAbsoluteRecurrenceTypeNone);
+      if (APP_CONTROL_ERROR_NONE != ret) {
+        LogAndReportError(
+            PlatformResult(ErrorCode::ABORT_ERR, "Fail to add data from app_control."), &out,
+            ("Fail to add data from app_control: %d (%s)", ret, get_error_message(ret)));
+        return;
+      }
+
+      platform_result = CommonNotification::SetAppControl(notification_handle, app_control);
+      if (!platform_result) {
+        LogAndReportError(
+            PlatformResult(platform_result.error_code(), platform_result.message().c_str()), &out);
+      }
+
+      ret = alarm_schedule_noti_once_at_date(notification_handle, &start_date, &alarm_id);
+    }
+  }
+
+  if (ALARM_ERROR_NONE != ret) {
+    if (ALARM_ERROR_INVALID_TIME == ret || ALARM_ERROR_INVALID_DATE == ret ||
+        ALARM_ERROR_INVALID_PARAMETER == ret) {
+      platform_result = PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid data.");
+    } else {
+      platform_result = PlatformResult(ErrorCode::ABORT_ERR, "Error while adding alarm to server.");
+    }
+
+    LogAndReportError(platform_result, &out,
+                      ("Error while add alarm to server: %d (%s)", ret, get_error_message(ret)));
+    return;
+  }
+
+  picojson::value result = picojson::value(picojson::object());
+  picojson::object& result_obj = result.get<picojson::object>();
+
+  if (alarm_type == kAlarmRelative) {
+    int period = 0;
+    ret = alarm_get_scheduled_period(alarm_id, &period);
+    if (ALARM_ERROR_NONE != ret) {
+      LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred."), &out,
+                        ("Unknown error occurred: %d (%s)", ret, get_error_message(ret)));
+      return;
+    }
+    if (0 != period) {
+      result_obj.insert(std::make_pair("period", picojson::value(std::to_string(period))));
+    }
+  }
+
+  result_obj.insert(std::make_pair("id", picojson::value(std::to_string(alarm_id))));
+  ReportSuccess(result, out);
+}
+#endif
+
 void AlarmManager::Remove(const picojson::value& args, picojson::object& out) {
   ScopeLogger();
   CHECK_PRIVILEGE_ACCESS(kPrivilegeAlarm, &out);
@@ -319,18 +528,30 @@ PlatformResult AlarmManager::GetAlarm(int id, picojson::object& obj) {
   char* alarm_type = nullptr;
   char* date_string = nullptr;
   char* delay_string = nullptr;
+  notification_h notification_handle = nullptr;
 
   SCOPE_EXIT {
     app_control_destroy(app_control);
     free(alarm_type);
     free(date_string);
     free(delay_string);
+    notification_free(notification_handle);
   };
 
-  ret = alarm_get_app_control(id, &app_control);
-  if (ALARM_ERROR_NONE != ret) {
-    return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Alarm not found.",
-                              ("Alarm not found: %d (%s)", ret, get_error_message(ret)));
+  if (ALARM_ERROR_NONE != alarm_get_app_control(id, &app_control)) {
+    if (ALARM_ERROR_NONE != alarm_get_notification(id, &notification_handle)) {
+      return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Alarm not found.",
+                                ("Alarm not found: %d (%s)", ret, get_error_message(ret)));
+    } else {
+      PlatformResult platform_result = extension::notification::CommonNotification::GetAppControl(
+          notification_handle, &app_control);
+      if (!platform_result) {
+        return LogAndCreateResult(
+            platform_result.error_code(), platform_result.message().c_str(),
+            ("Failed to get AppControl: %d (%s)", static_cast<int>(platform_result.error_code()),
+             platform_result.message().c_str()));
+      }
+    }
   }
 
   ret = app_control_get_extra_data(app_control, kAlarmKeyType, &alarm_type);
@@ -392,6 +613,7 @@ PlatformResult AlarmManager::GetAlarm(int id, picojson::object& obj) {
           obj.insert(std::make_pair("second", picojson::value(picojson::array())))
               .first->second.get<picojson::array>();
 
+      using namespace util;
       if (byDayValue & ALARM_WEEK_FLAG_SUNDAY) array.push_back(picojson::value(kSundayShort));
       if (byDayValue & ALARM_WEEK_FLAG_MONDAY) array.push_back(picojson::value(kMondayShort));
       if (byDayValue & ALARM_WEEK_FLAG_TUESDAY) array.push_back(picojson::value(kTuesdayShort));
@@ -412,10 +634,11 @@ PlatformResult AlarmManager::GetAlarm(int id, picojson::object& obj) {
                                 ("Unknown error occurred: %d (%s)", ret, get_error_message(ret)));
     }
 
-    ret = app_control_get_extra_data(app_control, kAlarmRelativeDelayKey, &delay_string);
-    if (APP_CONTROL_ERROR_NONE != ret) {
-      return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Failed to get data.",
-                                ("Failed to get data: %d (%s)", ret, get_error_message(ret)));
+    int ret_app = app_control_get_extra_data(app_control, kAlarmRelativeDelayKey, &delay_string);
+    if (APP_CONTROL_ERROR_NONE != ret_app) {
+      return LogAndCreateResult(
+          ErrorCode::NOT_FOUND_ERR, "Failed to get data.",
+          ("Failed to get data: %d (%s)", ret_app, get_error_message(ret_app)));
     }
 
     obj.insert(std::make_pair("type", picojson::value(kAlarmRelative)));
@@ -453,6 +676,55 @@ void AlarmManager::Get(const picojson::value& args, picojson::object& out) {
   }
 }
 
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+void AlarmManager::GetAlarmNotification(const picojson::value& args, picojson::object& out) {
+  using namespace extension::notification;
+  ScopeLogger();
+
+  int alarm_id = 0;
+  int ret = ALARM_ERROR_NONE;
+  notification_h notification_handle = nullptr;
+  PlatformResult platform_result = PlatformResult(ErrorCode::NO_ERROR);
+
+  SCOPE_EXIT {
+    notification_free(notification_handle);
+  };
+
+  if (args.contains("id") && args.get("id").is<double>()) {
+    alarm_id = static_cast<int>(args.get("id").get<double>());
+  }
+
+  ret = alarm_get_notification(alarm_id, &notification_handle);
+
+  if (ALARM_ERROR_NONE != ret) {
+    if (ALARM_ERROR_INVALID_PARAMETER == ret) {
+      platform_result =
+          PlatformResult(ErrorCode::NOT_FOUND_ERR, "Alarm with given ID was not found.");
+    } else {
+      platform_result = PlatformResult(ErrorCode::ABORT_ERR, "Failed to get notification.");
+    }
+    LogAndReportError(platform_result, &out);
+  }
+
+  app_control_h app_control = nullptr;
+  platform_result = CommonNotification::GetAppControl(notification_handle, &app_control);
+
+  if (!platform_result) {
+    LogAndReportError(platform_result, &out);
+  }
+
+  picojson::value result = picojson::value(picojson::object());
+  picojson::object& result_obj = result.get<picojson::object>();
+
+  platform_result = UserNotification::ToJson(-1, notification_handle, app_control, &result_obj);
+
+  if (ALARM_ERROR_NONE != ret) {
+    LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Failed ToJson()."), &out);
+  }
+
+  ReportSuccess(result, out);
+}
+#endif
 static bool AlarmIterateCB(int alarm_id, void* user_data) {
   ScopeLogger();
 
@@ -461,10 +733,10 @@ static bool AlarmIterateCB(int alarm_id, void* user_data) {
   alarm_ids->push_back(alarm_id);
   return true;
 }
+#include <stdio.h>
 
 void AlarmManager::GetAll(const picojson::value& args, picojson::object& out) {
   ScopeLogger();
-
   std::vector<int> alarm_ids;
   int ret = alarm_foreach_registered_alarm(AlarmIterateCB, &alarm_ids);
 
@@ -534,7 +806,6 @@ void AlarmManager::GetRemainingSeconds(const picojson::value& args, picojson::ob
 
 void AlarmManager::GetNextScheduledDate(const picojson::value& args, picojson::object& out) {
   ScopeLogger();
-
   int id = 0;
 
   if (args.contains("id") && args.get("id").is<double>()) {
index 1e3b4b1..df5559b 100644 (file)
@@ -34,6 +34,10 @@ class AlarmManager {
   void Get(const picojson::value& args, picojson::object& out);
   void GetAll(const picojson::value& args, picojson::object& out);
 
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+  void AddAlarmNotification(const picojson::value& args, picojson::object& out);
+  void GetAlarmNotification(const picojson::value& args, picojson::object& out);
+#endif
   // AlarmRelative
   void GetRemainingSeconds(const picojson::value& args, picojson::object& out);
   // AlarmAbsolute
index 7917e1d..31e1862 100644 (file)
@@ -24,6 +24,14 @@ namespace extension {
 namespace alarm {
 namespace util {
 
+const char* kSundayShort = "SU";
+const char* kMondayShort = "MO";
+const char* kTuesdayShort = "TU";
+const char* kWednesdayShort = "WE";
+const char* kThuesdayShort = "TH";
+const char* kFridayShort = "FR";
+const char* kSaturdayShort = "SA";
+
 using namespace common;
 
 PlatformResult AppControlToService(const picojson::object& obj, app_control_h* app_control) {
@@ -144,6 +152,31 @@ PlatformResult AppControlToServiceExtraData(const picojson::object& app_obj,
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
+PlatformResult ArrayDaysToMask(const picojson::array& days_of_the_week, int* repeat_value) {
+  ScopeLogger();
+  for (auto iter = days_of_the_week.begin(); iter != days_of_the_week.end(); ++iter) {
+    auto day = (*iter).get<std::string>();
+    if (kSundayShort == day) {
+      *repeat_value |= ALARM_WEEK_FLAG_SUNDAY;
+    } else if (kMondayShort == day) {
+      *repeat_value |= ALARM_WEEK_FLAG_MONDAY;
+    } else if (kTuesdayShort == day) {
+      *repeat_value |= ALARM_WEEK_FLAG_TUESDAY;
+    } else if (kWednesdayShort == day) {
+      *repeat_value |= ALARM_WEEK_FLAG_WEDNESDAY;
+    } else if (kThuesdayShort == day) {
+      *repeat_value |= ALARM_WEEK_FLAG_THURSDAY;
+    } else if (kFridayShort == day) {
+      *repeat_value |= ALARM_WEEK_FLAG_FRIDAY;
+    } else if (kSaturdayShort == day) {
+      *repeat_value |= ALARM_WEEK_FLAG_SATURDAY;
+    } else {
+      return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "Invalid days of the week value.");
+    }
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
 }  // util
 }  // alarm
 }  // extension
index 85e5345..c1a7fe2 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef ALARM_ALARM_UTILS_H_
 #define ALARM_ALARM_UTILS_H_
 
+#include <app_alarm.h>
 #include <app_control.h>
 
 #include "common/picojson.h"
@@ -26,9 +27,18 @@ namespace extension {
 namespace alarm {
 namespace util {
 
+extern const char* kSundayShort;
+extern const char* kMondayShort;
+extern const char* kTuesdayShort;
+extern const char* kWednesdayShort;
+extern const char* kThuesdayShort;
+extern const char* kFridayShort;
+extern const char* kSaturdayShort;
+
 common::PlatformResult AppControlToService(const picojson::object& obj, app_control_h* app_control);
 common::PlatformResult AppControlToServiceExtraData(const picojson::object& app_obj,
                                                     app_control_h* app_control);
+common::PlatformResult ArrayDaysToMask(const picojson::array& days_of_the_week, int* repeat_value);
 }  // util
 }  // alarm
 }  // extension
index 40b614f..29acdf2 100644 (file)
@@ -33,7 +33,8 @@
             'packages': [
               'aul',
               'capi-appfw-app-manager',
-              'capi-appfw-application',
+              'capi-appfw-app-control',
+              'capi-appfw-event',
               'capi-appfw-package-manager',
               'pkgmgr',
               'pkgmgr-info',
             ]
           },
         }],
+        ['extension_host_os == "mobile" or extension_host_os == "wearable"', {
+          'variables': {
+            'packages': [
+              'capi-context',
+            ]
+          }
+        }],
       ],
     },
   ],
index 6613b4b..70586ee 100755 (executable)
@@ -26,6 +26,11 @@ var ApplicationControlLaunchMode = {
     GROUP: 'GROUP'
 };
 
+var ApplicationUsageMode = {
+    RECENTLY: 'RECENTLY',
+    FREQUENTLY: 'FREQUENTLY'
+};
+
 //  TODO: Please uncomment below lines when system events is ready
 //var SystemEvent = {
 //  BATTERY_CHARGER_STATUS: 'BATTERY_CHARGER_STATUS',
@@ -508,6 +513,170 @@ ApplicationManager.prototype.getAppMetaData = function() {
     }
 };
 
+ApplicationManager.prototype.getBatteryUsageInfo = function() {
+    var args = AV.validateMethod(arguments, [
+        {
+            name: 'successCallback',
+            type: AV.Types.FUNCTION
+        },
+        {
+            name: 'errorCallback',
+            type: AV.Types.FUNCTION,
+            optional: true,
+            nullable: true
+        },
+        {
+            name: 'days',
+            type: AV.Types.LONG,
+            optional: true,
+            nullable: true
+        },
+        {
+            name: 'limit',
+            type: AV.Types.LONG,
+            optional: true,
+            nullable: true
+        }
+    ]);
+
+    var callArgs = {};
+
+    if (!T.isNullOrUndefined(args.days)) {
+        callArgs.days = args.days;
+    }
+
+    if (!T.isNullOrUndefined(args.limit)) {
+        callArgs.limit = args.limit;
+    }
+
+    var callback = function(result) {
+        if (native.isFailure(result)) {
+            native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+        } else {
+            var data = native.getResultObject(result);
+            var resultArray = [];
+            data.forEach(function(i) {
+                resultArray.push(new ApplicationBatteryUsage(i));
+            });
+            args.successCallback(resultArray);
+        }
+    };
+
+    var result = native.call(
+        'ApplicationManager_getBatteryUsageInfo',
+        callArgs,
+        callback
+    );
+    if (native.isFailure(result)) {
+        throw native.getErrorObject(result);
+    }
+};
+
+ApplicationManager.prototype.getAppsUsageInfo = function() {
+    var args = AV.validateMethod(arguments, [
+        {
+            name: 'successCallback',
+            type: AV.Types.FUNCTION
+        },
+        {
+            name: 'errorCallback',
+            type: AV.Types.FUNCTION,
+            optional: true,
+            nullable: true
+        },
+        {
+            name: 'mode',
+            type: AV.Types.ENUM,
+            values: T.getValues(ApplicationUsageMode),
+            optional: true,
+            nullable: true
+        },
+        {
+            name: 'filter',
+            type: AV.Types.DICTIONARY,
+            optional: true,
+            nullable: true
+        },
+        {
+            name: 'limit',
+            type: AV.Types.LONG,
+            optional: true,
+            nullable: true
+        }
+    ]);
+
+    var callArgs = {};
+
+    if (!T.isNullOrUndefined(args.mode)) {
+        callArgs.mode = args.mode;
+    }
+
+    if (!T.isNullOrUndefined(args.filter) && typeof args.filter !== 'object') {
+        setTimeout(function() {
+            native.callIfPossible(
+                args.errorCallback,
+                new WebAPIException(
+                    WebAPIException.INVALID_VALUES_ERR,
+                    'filter must be an object.'
+                )
+            );
+        }, 0);
+        return;
+    }
+
+    callArgs.filter = {};
+    if (!T.isNullOrUndefined(args.filter)) {
+        var filter = args.filter;
+        if (!T.isNullOrUndefined(filter.timeSpan)) {
+            callArgs.filter.timeSpan = Converter.toLong(filter.timeSpan);
+        } else {
+            if (!T.isNullOrUndefined(filter.startTime)) {
+                if (filter.startTime instanceof Date) {
+                    callArgs.filter.startTime = filter.startTime.getTime() / 1000;
+                } else {
+                    throw new WebAPIException(
+                        WebAPIException.TYPE_MISMATCH_ERR,
+                        'startTime given with invalid type.'
+                    );
+                }
+            }
+
+            if (!T.isNullOrUndefined(filter.endTime)) {
+                if (filter.endTime instanceof Date) {
+                    callArgs.filter.endTime = filter.endTime.getTime() / 1000;
+                } else {
+                    throw new WebAPIException(
+                        WebAPIException.TYPE_MISMATCH_ERR,
+                        'endTime given with invalid type.'
+                    );
+                }
+            }
+        }
+    }
+
+    if (!T.isNullOrUndefined(args.limit)) {
+        callArgs.limit = args.limit;
+    }
+
+    var callback = function(result) {
+        if (native.isFailure(result)) {
+            native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+        } else {
+            var data = native.getResultObject(result);
+            var resultArray = [];
+            data.forEach(function(i) {
+                resultArray.push(new ApplicationUsage(i));
+            });
+            args.successCallback(resultArray);
+        }
+    };
+
+    var result = native.call('ApplicationManager_getAppsUsageInfo', callArgs, callback);
+    if (native.isFailure(result)) {
+        throw native.getErrorObject(result);
+    }
+};
+
 function ListenerManager(native, listenerName) {
     this.listeners = {};
     this.nextId = 1;
@@ -617,6 +786,120 @@ ApplicationManager.prototype.removeAppInfoEventListener = function() {
     applicationEventListener.removeListener(args.watchId);
 };
 
+function StatusListenerManager(native, listenerName) {
+    this.listeners = {};
+    this.listenersCount = 0;
+    this.nextId = 1;
+    this.nativeSet = false;
+    this.native = native;
+    this.listenerName = listenerName;
+}
+
+StatusListenerManager.prototype.onListenerCalled = function(msg) {
+    var statusType = msg.statusType;
+    var app_id = msg.appId;
+
+    for (var watchId in this.listeners) {
+        if (this.listeners.hasOwnProperty(watchId)) {
+            var listener = this.listeners[watchId];
+            if (!listener.appId || listener.appId === app_id) {
+                listener.callback(app_id, statusType);
+            }
+        }
+    }
+};
+
+StatusListenerManager.prototype.addListener = function(callback, appId) {
+    if (!this.nativeSet) {
+        var result = this.native.callSync(
+            'ApplicationManager_addAppStatusChangeListener'
+        );
+        if (this.native.isFailure(result)) {
+            throw this.native.getErrorObject(result);
+        }
+
+        this.native.addListener(this.listenerName, this.onListenerCalled.bind(this));
+        this.nativeSet = true;
+    }
+
+    var listener = {
+        callback: callback,
+        appId: appId
+    };
+
+    var id = this.nextId++;
+    this.listeners[id] = listener;
+    this.listenersCount++;
+
+    return id;
+};
+
+StatusListenerManager.prototype.removeListener = function(watchId) {
+    if (this.listeners.hasOwnProperty(watchId)) {
+        if (this.listenersCount > 1) {
+            delete this.listeners[watchId];
+            this.listenersCount--;
+            return;
+        }
+
+        if (this.nativeSet) {
+            var result = this.native.callSync(
+                'ApplicationManager_removeStatusChangeListener'
+            );
+            if (this.native.isFailure(result)) {
+                throw this.native.getErrorObject(result);
+            }
+
+            delete this.listeners[watchId];
+            this.listenersCount--;
+
+            this.native.removeListener(this.listenerName);
+            this.nativeSet = false;
+        }
+    }
+};
+
+var APP_STATUS_CHANGE_LISTENER = 'AppStatusChangeListener';
+var appStatusChangeListener = new StatusListenerManager(
+    native,
+    APP_STATUS_CHANGE_LISTENER
+);
+
+ApplicationManager.prototype.addAppStatusChangeListener = function() {
+    var args = AV.validateMethod(arguments, [
+        {
+            name: 'statusChangeListener',
+            type: AV.Types.FUNCTION
+        },
+        {
+            name: 'appId',
+            type: AV.Types.STRING,
+            optional: true,
+            nullable: true
+        }
+    ]);
+
+    if (args.appId !== undefined && args.appId !== null && !args.appId.length) {
+        throw new WebAPIException(
+            WebAPIException.INVALID_VALUES_ERR,
+            'Application id is empty'
+        );
+    }
+
+    return appStatusChangeListener.addListener(args.statusChangeListener, args.appId);
+};
+
+ApplicationManager.prototype.removeAppStatusChangeListener = function() {
+    var args = AV.validateMethod(arguments, [
+        {
+            name: 'watchId',
+            type: AV.Types.LONG
+        }
+    ]);
+
+    appStatusChangeListener.removeListener(args.watchId);
+};
+
 // class Application ////////////////////////////////////////////////////
 
 function Application(data) {
@@ -1135,7 +1418,7 @@ function ApplicationCertificate(data) {
     });
 }
 
-// class ApplicationMetaData ////////////////////////////////////////////////////
+// class ApplicationMetaData ///////////////////////////////////////////////////////
 function ApplicationMetaData(data) {
     Object.defineProperties(this, {
         key: {
@@ -1151,5 +1434,47 @@ function ApplicationMetaData(data) {
     });
 }
 
+//class ApplicationBatteryUsage ////////////////////////////////////////////////////
+function ApplicationBatteryUsage(data) {
+    Object.defineProperties(this, {
+        appId: {
+            value: data.appId,
+            writable: false,
+            enumerable: true
+        },
+        batteryUsage: {
+            value: data.batteryUsage,
+            writable: false,
+            enumerable: true
+        }
+    });
+}
+
+//class ApplicationUsage ////////////////////////////////////////////////////////
+function ApplicationUsage(data) {
+    Object.defineProperties(this, {
+        appId: {
+            value: data.appId,
+            writable: false,
+            enumerable: true
+        },
+        totalCount: {
+            value: data.totalCount,
+            writable: false,
+            enumerable: true
+        },
+        totalDuration: {
+            value: data.totalDuration,
+            writable: false,
+            enumerable: true
+        },
+        lastTime: {
+            value: new Date(data.lastTime * 1000),
+            writable: false,
+            enumerable: true
+        }
+    });
+}
+
 // exports ////////////////////////////////////////////////////
 exports = new ApplicationManager();
index 76f1d32..b0a0ea2 100644 (file)
@@ -33,6 +33,7 @@ const std::string kPrivilegeAppManagerCertificate =
 const std::string kPrivilegeAppManagerKill = "http://tizen.org/privilege/appmanager.kill";
 const std::string kPrivilegeApplicationInfo = "http://tizen.org/privilege/application.info";
 const std::string kPrivilegeApplicationLaunch = "http://tizen.org/privilege/application.launch";
+const std::string kPrivilegeAppHistoryRead = "http://tizen.org/privilege/apphistory.read";
 }  // namespace
 
 using namespace common;
@@ -61,6 +62,8 @@ ApplicationInstance::ApplicationInstance() : manager_(*this) {
   REGISTER_SYNC("ApplicationManager_getAppMetaData", GetAppMetaData);
   REGISTER_SYNC("ApplicationManager_addAppInfoEventListener", AddAppInfoEventListener);
   REGISTER_SYNC("ApplicationManager_removeAppInfoEventListener", RemoveAppInfoEventListener);
+  REGISTER_SYNC("ApplicationManager_addAppStatusChangeListener", AddStatusListener);
+  REGISTER_SYNC("ApplicationManager_removeStatusChangeListener", RemoveStatusListener);
 
   // Application
   REGISTER_SYNC("Application_getRequestedAppControl", GetRequestedAppControl);
@@ -86,6 +89,8 @@ ApplicationInstance::ApplicationInstance() : manager_(*this) {
   REGISTER_ASYNC("ApplicationManager_findAppControl", FindAppControl);
   REGISTER_ASYNC("ApplicationManager_getAppsContext", GetAppsContext);
   REGISTER_ASYNC("ApplicationManager_getAppsInfo", GetAppsInfo);
+  REGISTER_ASYNC("ApplicationManager_getAppsUsageInfo", GetAppsUsageInfo);
+  REGISTER_ASYNC("ApplicationManager_getBatteryUsageInfo", GetBatteryUsageInfo);
 #undef REGISTER_ASYNC
 }
 
@@ -158,6 +163,20 @@ void ApplicationInstance::GetAppMetaData(const picojson::value& args, picojson::
   manager_.GetAppMetaData(app_id, &out);
 }
 
+void ApplicationInstance::GetBatteryUsageInfo(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeAppHistoryRead, &out);
+
+  manager_.GetBatteryUsageInfo(args, &out);
+}
+
+void ApplicationInstance::GetAppsUsageInfo(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeAppHistoryRead, &out);
+
+  manager_.GetAppsUsageInfo(args, &out);
+}
+
 void ApplicationInstance::AddAppInfoEventListener(const picojson::value& args,
                                                   picojson::object& out) {
   ScopeLogger();
@@ -268,14 +287,14 @@ void ApplicationInstance::AddEventListener(const picojson::value& args, picojson
 
   const std::string& event_name = args.get("name").get<std::string>();
 
-  LOGGER(DEBUG) << "event_name: " << event_name;
+  LoggerD("event_name: %s", event_name.c_str());
 
   JsonCallback cb = [this, args](picojson::value* event) -> void {
     picojson::object& event_o = event->get<picojson::object>();
     event_o["listenerId"] = args.get("listenerId");
-    LOGGER(DEBUG) << event->serialize().c_str();
+    LoggerD("%s", event->serialize().c_str());
     Instance::PostMessage(this, event->serialize().c_str());
-    LOGGER(DEBUG) << event->serialize().c_str();
+    LoggerD("%s", event->serialize().c_str());
   };
 
   PlatformResult result = manager_.StartEventListener(event_name, cb);
@@ -291,10 +310,36 @@ void ApplicationInstance::RemoveEventListener(const picojson::value& args, picoj
 
   const std::string& event_name = args.get("name").get<std::string>();
 
-  LOGGER(DEBUG) << "event_name: " << event_name;
+  LoggerD("event_name: %s", event_name.c_str());
 
   manager_.StopEventListener(event_name);
 }
 
+void ApplicationInstance::AddStatusListener(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  JsonCallback cb = [this](picojson::value* event) -> void {
+    Instance::PostMessage(this, event->serialize().c_str());
+  };
+
+  PlatformResult result = manager_.StartStatusListener(cb);
+  if (result) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void ApplicationInstance::RemoveStatusListener(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  PlatformResult result = manager_.StopStatusChangeListener();
+  if (result) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
 }  // namespace application
 }  // namespace extension
index e43cb1c..8cafed2 100644 (file)
@@ -39,6 +39,8 @@ class ApplicationInstance : public common::ParsedInstance {
   void GetAppCerts(const picojson::value& args, picojson::object& out);
   void GetAppSharedURI(const picojson::value& args, picojson::object& out);
   void GetAppMetaData(const picojson::value& args, picojson::object& out);
+  void GetBatteryUsageInfo(const picojson::value& args, picojson::object& out);
+  void GetAppsUsageInfo(const picojson::value& args, picojson::object& out);
   void AddAppInfoEventListener(const picojson::value& args, picojson::object& out);
   void RemoveAppInfoEventListener(const picojson::value& args, picojson::object& out);
   void GetRequestedAppControl(const picojson::value& args, picojson::object& out);
@@ -55,6 +57,8 @@ class ApplicationInstance : public common::ParsedInstance {
   void BroadcastTrustedEvent(const picojson::value& args, picojson::object& out);
   void AddEventListener(const picojson::value& args, picojson::object& out);
   void RemoveEventListener(const picojson::value& args, picojson::object& out);
+  void AddStatusListener(const picojson::value& args, picojson::object& out);
+  void RemoveStatusListener(const picojson::value& args, picojson::object& out);
 
   ApplicationManager manager_;
   Application current_application_;
index 3d8ccd6..69e2a55 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <app_control_internal.h>
 #include <app_info.h>
-#include <app_manager.h>
 #include <app_manager_extension.h>
 #include <appsvc.h>
 #include <aul.h>
@@ -68,6 +67,12 @@ const std::string kOnInstalled = "oninstalled";
 const std::string kOnUpdated = "onupdated";
 const std::string kOnUninstalled = "onuninstalled";
 const std::string kData = "data";
+const std::string kStatusType = "statusType";
+const std::string kAppId = "appId";
+const std::string kListenerId = "listenerId";
+const std::string kAppStatusChangeListener = "AppStatusChangeListener";
+const std::string kAppUsageModeFrequently = "FREQUENTLY";
+const std::string kAppUsageModeRecently = "RECENTLY";
 
 const std::map<std::string, std::string> event_map_ = {
     {SYSTEM_EVENT_BATTERY_CHARGER_STATUS, EVENT_KEY_BATTERY_CHARGER_STATUS},
@@ -92,18 +97,27 @@ const std::map<std::string, std::string> event_map_ = {
     {SYSTEM_EVENT_MOBILE_DATA_STATE, EVENT_KEY_MOBILE_DATA_STATE},
     {SYSTEM_EVENT_DATA_ROAMING_STATE, EVENT_KEY_DATA_ROAMING_STATE},
     {SYSTEM_EVENT_FONT_SET, EVENT_KEY_FONT_SET}};
+
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+const int kMaximumBatteryRetrievedObjects = 30;
+const int kMaximumAppsRetrievedObjects = 10;
+const int kDefaultPeriodOfTime = 30;
+#endif
 }
 
 ApplicationManager::ApplicationManager(ApplicationInstance& instance)
     : pkgmgr_client_handle_(nullptr),
       pkgmgr_client_uninstall_handle_(nullptr),
-      instance_(instance) {
+      instance_(instance),
+      app_status_handle_(nullptr) {
   ScopeLogger();
 }
 
 ApplicationManager::~ApplicationManager() {
   ScopeLogger();
   StopAppInfoEventListener();
+  StopStatusChangeListener();
+
   for (auto it = event_handler_map_.begin(); it != event_handler_map_.end();) {
     int ret = event_remove_event_handler(it->second);
     if (EVENT_ERROR_NONE != ret) {
@@ -111,6 +125,13 @@ ApplicationManager::~ApplicationManager() {
     }
     it = event_handler_map_.erase(it);
   }
+
+  if (app_status_handle_) {
+    int ret = app_manager_event_destroy(app_status_handle_);
+    if (APP_MANAGER_ERROR_NONE != ret) {
+      LoggerE("app_manager_event_destroy failed, error: %d", ret);
+    }
+  }
 }
 
 void ApplicationManager::GetCurrentApplication(const std::string& app_id, picojson::object* out) {
@@ -1129,6 +1150,268 @@ void ApplicationManager::GetAppSharedUri(const std::string& app_id, picojson::ob
   ReportSuccess(result, *out);
 }
 
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+PlatformResult ApplicationManager::BatteryUsageFilter(const picojson::value& args,
+                                                      const context_history_filter_h filter,
+                                                      context_history_data_e* data_type_out) {
+  ScopeLogger();
+  int ret = CONTEXT_HISTORY_ERROR_NONE;
+  int limit = kMaximumBatteryRetrievedObjects;
+  if (args.contains("limit")) {
+    limit = static_cast<int>(args.get("limit").get<double>());
+  }
+
+  ret = context_history_filter_set_int(filter, CONTEXT_HISTORY_FILTER_RESULT_SIZE, limit);
+
+  if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        ErrorCode::INVALID_VALUES_ERR, "limit given with invalid value.",
+        ("limit given with invalid value: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  context_history_data_e data_type_in = CONTEXT_HISTORY_RECENT_BATTERY_USAGE;
+
+  if (args.contains("days")) {
+    const int days = static_cast<int>(args.get("days").get<double>());
+    data_type_in = CONTEXT_HISTORY_BATTERY_USAGE;
+    ret = context_history_filter_set_int(filter, CONTEXT_HISTORY_FILTER_TIME_SPAN, days);
+
+    if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+      return LogAndCreateResult(
+          ErrorCode::INVALID_VALUES_ERR, "days given with invalid value.",
+          ("days given with invalid value: %d (%s)", ret, get_error_message(ret)));
+    }
+  }
+
+  *data_type_out = data_type_in;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult ApplicationManager::BatteryUsageAttributes(const context_history_record_h record,
+                                                          picojson::object* object) {
+  ScopeLogger();
+
+  int ret = CONTEXT_HISTORY_ERROR_NONE;
+  double amount = 0.0;
+  char* app_id = nullptr;
+  SCOPE_EXIT {
+    free(app_id);
+  };
+
+  ret = context_history_record_get_string(record, CONTEXT_HISTORY_APP_ID, &app_id);
+  if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::ABORT_ERR, "Failed to get string.",
+                              ("Failed to get string: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  ret = context_history_record_get_double(record, CONTEXT_HISTORY_TOTAL_AMOUNT, &amount);
+  if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::ABORT_ERR, "Failed to get amount.",
+                              ("Failed to get amount: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  object->insert(std::make_pair("appId", picojson::value(app_id)));
+  object->insert(std::make_pair("batteryUsage", picojson::value(amount)));
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult ApplicationManager::AppsUsageFilter(const picojson::value& args,
+                                                   const context_history_filter_h filter,
+                                                   context_history_data_e* data_type_out) {
+  ScopeLogger();
+  int ret = CONTEXT_HISTORY_ERROR_NONE;
+  int limit = kMaximumAppsRetrievedObjects;
+  if (args.contains("limit")) {
+    limit = static_cast<int>(args.get("limit").get<double>());
+  }
+
+  ret = context_history_filter_set_int(filter, CONTEXT_HISTORY_FILTER_RESULT_SIZE, limit);
+  if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        ErrorCode::INVALID_VALUES_ERR, "limit given with invalid value.",
+        ("limit given with invalid value: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  context_history_data_e data_type_in = CONTEXT_HISTORY_FREQUENTLY_USED_APP;
+  if (args.contains("mode") && kAppUsageModeRecently == args.get("mode").get<std::string>()) {
+    data_type_in = CONTEXT_HISTORY_RECENTLY_USED_APP;
+  }
+
+  int time_span = kDefaultPeriodOfTime;
+  const picojson::object& JS_filter = args.get("filter").get<picojson::object>();
+  auto time_span_iter = JS_filter.find("timeSpan");
+  if (JS_filter.end() != time_span_iter || (JS_filter.end() == JS_filter.find("startTime") &&
+                                            JS_filter.end() == JS_filter.find("endTime"))) {
+    // In the second case, we treat the filter object just like an empty object.
+    // The default value of filter will be used instead.
+    if (JS_filter.end() != time_span_iter) {
+      time_span = static_cast<int>(time_span_iter->second.get<double>());
+    }
+    ret = context_history_filter_set_int(filter, CONTEXT_HISTORY_FILTER_TIME_SPAN, time_span);
+    // context_history_filter_set_int may return only success or
+    // CONTEXT_HISTORY_ERROR_INVALID_PARAMETER
+    // Although this should never happen, it's better to check ret's value
+    if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::ABORT_ERR,
+                                "Error while setting the default TIME_SPAN value.",
+                                ("Error while setting the default TIME_SPAN value: %d (%s)", ret,
+                                 get_error_message(ret)));
+    }
+  } else {
+    auto start_time_iter = JS_filter.find("startTime");
+    auto end_time_iter = JS_filter.find("endTime");
+    if (start_time_iter != JS_filter.end()) {
+      int start_time = static_cast<int>(start_time_iter->second.get<double>());
+      ret = context_history_filter_set_int(filter, CONTEXT_HISTORY_FILTER_START_TIME, start_time);
+      if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+        return LogAndCreateResult(
+            ErrorCode::INVALID_VALUES_ERR, "startTime given with invalid value.",
+            ("startTime given with invalid value: %d (%s)", ret, get_error_message(ret)));
+      }
+    }
+    if (end_time_iter != JS_filter.end()) {
+      int end_time = static_cast<int>(end_time_iter->second.get<double>());
+      ret = context_history_filter_set_int(filter, CONTEXT_HISTORY_FILTER_END_TIME, end_time);
+      if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+        return LogAndCreateResult(
+            ErrorCode::INVALID_VALUES_ERR, "endTime given with invalid value.",
+            ("endTime given with invalid value: %d (%s)", ret, get_error_message(ret)));
+      }
+    }
+  }
+
+  *data_type_out = data_type_in;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult ApplicationManager::AppsUsageAttributes(const context_history_record_h record,
+                                                       picojson::object* object) {
+  ScopeLogger();
+
+  int ret = CONTEXT_HISTORY_ERROR_NONE;
+  int total_count = 0;
+  int total_duration = 0;
+  int last_time = 0;
+  char* app_id = nullptr;
+  SCOPE_EXIT {
+    free(app_id);
+  };
+
+  ret = context_history_record_get_string(record, CONTEXT_HISTORY_APP_ID, &app_id);
+  if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::ABORT_ERR, "Failed to get string.",
+                              ("Failed to get string: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  ret = context_history_record_get_int(record, CONTEXT_HISTORY_TOTAL_COUNT, &total_count);
+  if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::ABORT_ERR, "Failed to get total count.",
+                              ("Failed to get total count: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  ret = context_history_record_get_int(record, CONTEXT_HISTORY_TOTAL_DURATION, &total_duration);
+  if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        ErrorCode::ABORT_ERR, "Failed to get total duration.",
+        ("Failed to get total duration: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  ret = context_history_record_get_int(record, CONTEXT_HISTORY_LAST_TIME, &last_time);
+  if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::ABORT_ERR, "Failed to get last time.",
+                              ("Failed to get last time: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  object->insert(std::make_pair("appId", picojson::value(app_id)));
+  object->insert(std::make_pair("totalCount", picojson::value(static_cast<double>(total_count))));
+  object->insert(
+      std::make_pair("totalDuration", picojson::value(static_cast<double>(total_duration))));
+  object->insert(std::make_pair("lastTime", picojson::value(static_cast<double>(last_time))));
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+#endif
+
+void ApplicationManager::GetBatteryUsageInfo(const picojson::value& args, picojson::object* out) {
+  ScopeLogger();
+
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+  int callback_id = -1;
+  const auto& callback = args.get(kCallbackId);
+  if (callback.is<double>()) {
+    callback_id = static_cast<int>(callback.get<double>());
+  }
+
+  auto get_battery_usage = [args](const std::shared_ptr<picojson::value>& response) -> void {
+    ScopeLogger();
+    PlatformResult result = ApplicationManager::GetContextHistory(
+        args, &response.get()->get<picojson::object>(), &ApplicationManager::BatteryUsageFilter,
+        &ApplicationManager::BatteryUsageAttributes);
+    if (!result) {
+      LogAndReportError(result, &response.get()->get<picojson::object>());
+    }
+  };
+
+  auto get_battery_usage_response =
+      [this, callback_id](const std::shared_ptr<picojson::value>& response) -> void {
+    ScopeLogger();
+    picojson::object& obj = response->get<picojson::object>();
+    obj.insert(std::make_pair(kCallbackId, picojson::value(static_cast<double>(callback_id))));
+    Instance::PostMessage(&this->instance_, response->serialize().c_str());
+  };
+
+  auto data = std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+
+  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"));
+#endif
+}
+
+void ApplicationManager::GetAppsUsageInfo(const picojson::value& args, picojson::object* out) {
+  ScopeLogger();
+
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+  int callback_id = static_cast<int>(args.get(kCallbackId).get<double>());
+
+  auto get_apps_usage = [args](const std::shared_ptr<picojson::value>& response) -> void {
+    ScopeLogger();
+    PlatformResult result = ApplicationManager::GetContextHistory(
+        args, &response.get()->get<picojson::object>(), &ApplicationManager::AppsUsageFilter,
+        &ApplicationManager::AppsUsageAttributes);
+    if (!result) {
+      LogAndReportError(result, &response.get()->get<picojson::object>());
+    }
+  };
+
+  auto get_apps_usage_response =
+      [this, callback_id](const std::shared_ptr<picojson::value>& response) -> void {
+    ScopeLogger();
+    picojson::object& obj = response->get<picojson::object>();
+    obj.insert(std::make_pair(kCallbackId, picojson::value(static_cast<double>(callback_id))));
+    Instance::PostMessage(&this->instance_, response->serialize().c_str());
+  };
+
+  auto data = std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+
+  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"));
+#endif
+}
+
 void ApplicationManager::GetAppMetaData(const std::string& app_id, picojson::object* out) {
   ScopeLogger();
 
@@ -1525,12 +1808,12 @@ void ApplicationManager::BroadcastEventHelper(const picojson::value& args, picoj
 }
 
 void ApplicationManager::OnEvent(const char* event_name, bundle* event_data, void* user_data) {
-  ScopeLogger("Event name is: '%f'", event_name);
+  ScopeLogger("Event name is: '%s'", event_name);
 
   ApplicationManager* manager = static_cast<ApplicationManager*>(user_data);
 
   if (!manager->event_callback_) {
-    LOGGER(DEBUG) << "No event listener registered, skipping.";
+    LoggerD("No event listener registered, skipping.");
     return;
   }
 
@@ -1567,14 +1850,14 @@ void ApplicationManager::OnEvent(const char* event_name, bundle* event_data, voi
     std::string err;
     picojson::parse(data, val, val + strlen(val), &err);
     if (!err.empty()) {
-      LOGGER(ERROR) << "Failed to parse bundle data: " << err;
+      LoggerE("Failed to parse bundle data: %s", err.c_str());
       return;
     }
 
     event_o["data"] = data;
   }
 
-  LOGGER(DEBUG) << "event_name is: " << event_name;
+  LoggerD("event_name is: %s", event_name);
   event_o["name"] = picojson::value(event_name);
 
   manager->event_callback_(&event);
@@ -1600,7 +1883,7 @@ PlatformResult ApplicationManager::StartEventListener(const std::string& event_n
   event_handler_map_[event_name] = event_handler;
 
   event_callback_ = callback;
-  LOGGER(DEBUG) << "event_add_event_handler success";
+  LoggerD("event_add_event_handler success");
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
@@ -1623,5 +1906,180 @@ void ApplicationManager::StopEventListener(const std::string& event_name) {
   }
 }
 
+void ApplicationManager::OnStatusEvent(const char* type, const char* app_id,
+                                       app_manager_event_type_e event_type,
+                                       app_manager_event_state_e event_state,
+                                       app_manager_event_h handle, void* user_data) {
+  ScopeLogger();
+
+  if (APP_MANAGER_EVENT_STATE_COMPLETED != event_state) {
+    LoggerD("State different from completed");
+    return;
+  }
+
+  ApplicationManager* manager = static_cast<ApplicationManager*>(user_data);
+
+  if (!manager || !manager->status_callback_) {
+    LoggerD("No event listener registered, skipping.");
+    return;
+  }
+
+  bool status_type;
+  switch (event_type) {
+    case APP_MANAGER_EVENT_ENABLE_APP:
+      status_type = true;
+      break;
+    case APP_MANAGER_EVENT_DISABLE_APP:
+      status_type = false;
+      break;
+    default:
+      LoggerD("Uknown status type skipping.");
+      return;
+  }
+
+  picojson::value event = picojson::value(picojson::object());
+  picojson::object& event_o = event.get<picojson::object>();
+
+  event_o[kStatusType] = picojson::value(status_type);
+  event_o[kAppId] = picojson::value(app_id);
+  event_o[kListenerId] = picojson::value(kAppStatusChangeListener);
+
+  manager->status_callback_(&event);
+}
+
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+PlatformResult ApplicationManager::GetContextHistory(
+    const picojson::value& args, picojson::object* out,
+    common::PlatformResult (*modify_filter_cb)(const picojson::value&,
+                                               const context_history_filter_h,
+                                               context_history_data_e* data_type),
+    common::PlatformResult (*add_attributes_to_object)(const context_history_record_h,
+                                                       picojson::object*)) {
+  ScopeLogger();
+  context_history_list_h list = nullptr;
+  context_history_h handle = nullptr;
+  context_history_filter_h filter = nullptr;
+
+  SCOPE_EXIT {
+    context_history_list_destroy(list);
+    context_history_destroy(handle);
+    context_history_filter_destroy(filter);
+  };
+
+  int ret = context_history_create(&handle);
+  if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        ErrorCode::ABORT_ERR, "Failed to create context handle.",
+        ("Failed to create context handle: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  ret = context_history_filter_create(&filter);
+  if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        ErrorCode::ABORT_ERR, "Failed to create filter handle.",
+        ("Failed to create filter handle: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  context_history_data_e data_type;
+
+  PlatformResult result = modify_filter_cb(args, filter, &data_type);
+  if (!result) {
+    return result;
+  }
+
+  picojson::value result_array = picojson::value(picojson::array());
+  picojson::array& array_obj = result_array.get<picojson::array>();
+
+  ret = context_history_get_list(handle, data_type, filter, &list);
+  if (CONTEXT_HISTORY_ERROR_NO_DATA == ret) {
+    ReportSuccess(result_array, *out);
+    return PlatformResult(ErrorCode::NO_ERROR);
+  } else if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::ABORT_ERR, "Failed to get list.",
+                              ("Failed to get list: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  int size = 0;
+  ret = context_history_list_get_count(list, &size);
+  if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::ABORT_ERR, "Failed to get list size.",
+                              ("Failed to get list size: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  array_obj.resize(size, picojson::value(picojson::object()));
+
+  for (int i = 0; i < size; ++i) {
+    context_history_record_h record = nullptr;
+    SCOPE_EXIT {
+      context_history_record_destroy(record);
+    };
+
+    ret = context_history_list_get_current(list, &record);
+    if (CONTEXT_HISTORY_ERROR_NONE != ret) {
+      return LogAndCreateResult(
+          ErrorCode::ABORT_ERR, "Failed to get current record.",
+          ("Failed to get current record: %d (%s)", ret, get_error_message(ret)));
+    }
+
+    result = add_attributes_to_object(record, &array_obj[i].get<picojson::object>());
+    if (!result) {
+      return result;
+    }
+
+    ret = context_history_list_move_next(list);
+    if (CONTEXT_HISTORY_ERROR_NONE != ret && CONTEXT_HISTORY_ERROR_NO_DATA != ret) {
+      return LogAndCreateResult(ErrorCode::ABORT_ERR, "Failed to move iterator.",
+                                ("Failed to move iterator: %d (%s)", ret, get_error_message(ret)));
+    }
+  }
+
+  ReportSuccess(result_array, *out);
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+#endif
+
+PlatformResult ApplicationManager::StartStatusListener(const JsonCallback& callback) {
+  ScopeLogger();
+
+  int ret = APP_MANAGER_ERROR_NONE;
+
+  if (!app_status_handle_) {
+    ret = app_manager_event_create(&app_status_handle_);
+    if (APP_MANAGER_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::ABORT_ERR, "Error while creating event handle",
+                                ("app_manager_event_create failed, error: %d", ret));
+    }
+
+    ret = app_manager_event_set_status(app_status_handle_, APP_MANAGER_EVENT_STATUS_TYPE_ALL);
+    if (APP_MANAGER_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::ABORT_ERR, "Error while setting status type",
+                                ("app_manager_event_set_status failed, error: %d", ret));
+    }
+  }
+
+  status_callback_ = callback;
+  ret = app_manager_set_event_cb(app_status_handle_, OnStatusEvent, this);
+  if (APP_MANAGER_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::ABORT_ERR, "Error while setting status listener",
+                              ("app_manager_set_event_cb failed, error: %d", ret));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult ApplicationManager::StopStatusChangeListener() {
+  ScopeLogger();
+
+  if (app_status_handle_) {
+    int ret = app_manager_unset_event_cb(app_status_handle_);
+    if (APP_MANAGER_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::ABORT_ERR, "Error while removing status listener",
+                                ("app_manager_unset_event_cb failed, error: %d", ret));
+    }
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
 }  // namespace application
 }  // namespace extension
index 7e7be7f..c1fa8ad 100644 (file)
 #define SRC_APPLICATION_APPLICATION_MANAGER_H__
 
 #include <app_event.h>
+#include <app_manager.h>
 #include <bundle.h>
 #include <package-manager.h>
 #include <pkgmgr-info.h>
 #include <functional>
+#include <functional>
 #include <memory>
 #include <string>
+#if defined(TIZEN_MOBILE)
+#include <context-service/context_history.h>
+#elif defined(TIZEN_WEARABLE)
+#include <context-service/wearable/context_history.h>
+#endif
 
 #include "common/picojson.h"
 #include "common/platform_result.h"
@@ -52,6 +59,8 @@ class ApplicationManager {
   void GetAppCerts(const std::string& app_id, picojson::object* out);
   void GetAppSharedUri(const std::string& app_id, picojson::object* out);
   void GetAppMetaData(const std::string& app_id, picojson::object* out);
+  void GetBatteryUsageInfo(const picojson::value& args, picojson::object* out);
+  void GetAppsUsageInfo(const picojson::value& args, picojson::object* out);
   void StartAppInfoEventListener(picojson::object* out);
   void StopAppInfoEventListener();
   void GetApplicationInformationSize(const picojson::value& args, picojson::object* out);
@@ -61,6 +70,8 @@ class ApplicationManager {
   common::PlatformResult StartEventListener(const std::string& event_name,
                                             const JsonCallback& callback);
   void StopEventListener(const std::string& event_name);
+  common::PlatformResult StartStatusListener(const JsonCallback& callback);
+  common::PlatformResult StopStatusChangeListener();
 
  private:
   char* GetPackageId(const std::string& app_id);
@@ -68,10 +79,36 @@ class ApplicationManager {
   pkgmgr_client* pkgmgr_client_handle_;
   pkgmgr_client* pkgmgr_client_uninstall_handle_;
   ApplicationInstance& instance_;
+  app_manager_event_h app_status_handle_;
 
   JsonCallback event_callback_;
+  JsonCallback status_callback_;
   std::map<std::string, event_handler_h> event_handler_map_;
   static void OnEvent(const char* event_name, bundle* event_data, void* user_data);
+  static void OnStatusEvent(const char* type, const char* app_id,
+                            app_manager_event_type_e event_type,
+                            app_manager_event_state_e event_state, app_manager_event_h handle,
+                            void* user_data);
+
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+  static common::PlatformResult GetContextHistory(
+      const picojson::value& args, picojson::object* out,
+      common::PlatformResult (*)(const picojson::value&, const context_history_filter_h,
+                                 context_history_data_e* data_type),
+      common::PlatformResult (*)(const context_history_record_h, picojson::object*));
+
+  static common::PlatformResult BatteryUsageFilter(const picojson::value&,
+                                                   const context_history_filter_h,
+                                                   context_history_data_e* data_type);
+  static common::PlatformResult BatteryUsageAttributes(const context_history_record_h,
+                                                       picojson::object*);
+
+  static common::PlatformResult AppsUsageFilter(const picojson::value&,
+                                                const context_history_filter_h,
+                                                context_history_data_e* data_type);
+  static common::PlatformResult AppsUsageAttributes(const context_history_record_h,
+                                                    picojson::object*);
+#endif
 };
 
 }  // namespace application
index 10e1c8b..8924616 100644 (file)
@@ -58,7 +58,7 @@ OperationCallbackData::~OperationCallbackData() {
 }
 
 void OperationCallbackData::setError(const ErrorCode& err_code, const std::string& err_message) {
-  ScopeLogger("Setting error, code is: [%d]", err_code);
+  ScopeLogger("Setting error, code is: [%d]", static_cast<int>(err_code));
   // store only first error
   if (!m_is_error) {
     m_err_code = err_code;
@@ -562,7 +562,7 @@ void ExtractAllProgressCallback::updateOverallProgress(unsigned long bytes_decom
   m_progress_overall = static_cast<double>(m_overall_decompressed + m_files_extracted) /
                        static_cast<double>(m_expected_decompressed_size + m_files_to_extract);
 
-  LoggerD("%s of %s - %f%% (%d/%d files)", bytesToReadableString(m_overall_decompressed).c_str(),
+  LoggerD("%s of %s - %f%% (%lu/%lu files)", bytesToReadableString(m_overall_decompressed).c_str(),
           bytesToReadableString(m_expected_decompressed_size).c_str(), m_progress_overall * 100.0,
           m_files_extracted, m_files_to_extract);
 }
index 39da1ec..7a9b795 100644 (file)
@@ -106,7 +106,7 @@ gboolean ArchiveFile::openTaskCompleteCB(void* data) {
     std::string fm_str;
     PlatformResult result = fileModeToString(archive_file->getFileMode(), &fm_str);
     if (result.error_code() != ErrorCode::NO_ERROR) {
-      LoggerE("%s (%d)", result.message().c_str(), result.error_code());
+      LoggerE("%s (%d)", result.message().c_str(), static_cast<int>(result.error_code()));
       delete callback;
       callback = NULL;
       return false;
@@ -204,7 +204,8 @@ void ArchiveFile::taskManagerThread(gpointer data, gpointer user_data) {
         delete callback;
         callback = NULL;
       } else if (ErrorCode::NO_ERROR != result.error_code()) {
-        LoggerE("taskManagerThread fails, %d: %s", result.error_code(), result.message().c_str());
+        LoggerE("taskManagerThread fails, %d: %s", static_cast<int>(result.error_code()),
+                result.message().c_str());
         callback->setError(result.error_code(), result.message().c_str());
         if (!g_idle_add(callErrorCallback, static_cast<void*>(callback))) {
           LoggerE("g_idle_add fails");
index 092ab22..7ee32b5 100644 (file)
@@ -85,7 +85,8 @@ ArchiveInstance::~ArchiveInstance() {
 void ArchiveInstance::PostError(const PlatformResult& e, double callback_id) {
   ScopeLogger();
 
-  LoggerE("Posting an error: %d, message: %s", e.error_code(), e.message().c_str());
+  LoggerE("Posting an error: %d, message: %s", static_cast<int>(e.error_code()),
+          e.message().c_str());
 
   picojson::value val = picojson::value(picojson::object());
   picojson::object& obj = val.get<picojson::object>();
index b2908fd..13d23f7 100644 (file)
@@ -132,7 +132,7 @@ PlatformResult Node::resolve(const PathPtr& path, NodePtr* node) {
     }
   }
 
-  if ((!S_ISDIR(info.st_mode)) & (!S_ISREG(info.st_mode)) && !S_ISLNK(info.st_mode)) {
+  if ((!S_ISDIR(info.st_mode)) && (!S_ISREG(info.st_mode)) && !S_ISLNK(info.st_mode)) {
     SLoggerE("File: [%s]", path->getFullPath().c_str());
     return LogAndCreateResult(ErrorCode::IO_ERR, "Platform node is of unsupported type.");
   }
@@ -197,22 +197,21 @@ PlatformResult Node::getChildNames(Node::NameList* out_name_list) const {
     return LogAndCreateResult(ErrorCode::IO_ERR, "Node has been deleted from platform.");
   }
 
-  int err = 0;
-  struct dirent entry = {0};
-  struct dirent* result = nullptr;
+  errno = 0;
+  struct dirent* entry = nullptr;
   NameList name_list;
-  while ((0 == (err = readdir_r(dir, &entry, &result))) && result) {
-    if (!strcmp(entry.d_name, ".") || !strncmp(entry.d_name, "..", 2)) {
+  while (nullptr != (entry = readdir(dir))) {
+    if (!strcmp(entry->d_name, ".") || !strncmp(entry->d_name, "..", 2)) {
       continue;
     }
-    name_list.push_back(entry.d_name);
+    name_list.push_back(entry->d_name);
   }
 
   if (closedir(dir) != 0) {
     return LogAndCreateResult(ErrorCode::IO_ERR, "Could not close platform node.");
   }
 
-  if (0 != err) {
+  if (0 != errno) {
     return LogAndCreateResult(ErrorCode::IO_ERR, "Error while reading directory.");
   }
 
@@ -239,17 +238,16 @@ PlatformResult Node::getChildNodes(NodeList* out_node_list) const {
     return LogAndCreateResult(ErrorCode::IO_ERR, "Node has been deleted from platform.");
   }
 
-  int err = 0;
-  struct dirent entry = {0};
-  struct dirent* result = nullptr;
+  errno = 0;
+  struct dirent* entry = nullptr;
   NodeList node_list;
-  while ((0 == (err = readdir_r(dir, &entry, &result))) && result) {
-    if (!strcmp(entry.d_name, ".") || !strncmp(entry.d_name, "..", 2)) {
+  while (nullptr != (entry = readdir(dir))) {
+    if (!strcmp(entry->d_name, ".") || !strncmp(entry->d_name, "..", 2)) {
       continue;
     }
 
     NodePtr node;
-    Node::resolve(*m_path + entry.d_name, &node);
+    Node::resolve(*m_path + entry->d_name, &node);
     node->setPermissions(getPermissions());  // inherit access rights
     node_list.push_back(node);
   }
@@ -259,7 +257,7 @@ PlatformResult Node::getChildNodes(NodeList* out_node_list) const {
     return LogAndCreateResult(ErrorCode::IO_ERR, "Could not close platform node.");
   }
 
-  if (0 != err) {
+  if (0 != errno) {
     SLoggerE("Path %s Perm %d", m_path->getFullPath().c_str(), m_perms);
     return LogAndCreateResult(ErrorCode::IO_ERR, "Error while reading directory.");
   }
@@ -536,14 +534,13 @@ PlatformResult Node::removeAsDirectory(const PathPtr& path, bool recursive) {
       SLoggerE("File %s", path->getFullPath().c_str());
       return LogAndCreateResult(ErrorCode::IO_ERR, "Node does not exist or access denied.");
     }
-    struct dirent entry = {0};
-    struct dirent* result = nullptr;
+    struct dirent* entry = nullptr;
     PlatformResult platform_result(ErrorCode::NO_ERROR);
-    while ((0 == (readdir_r(dir, &entry, &result))) && result) {
-      if (!strcmp(entry.d_name, ".") || !strncmp(entry.d_name, "..", 2)) {
+    while (nullptr != (entry = readdir(dir))) {
+      if (!strcmp(entry->d_name, ".") || !strncmp(entry->d_name, "..", 2)) {
         continue;
       }
-      PathPtr subPath = *path + entry.d_name;
+      PathPtr subPath = *path + entry->d_name;
       struct stat info;
       memset(&info, 0, sizeof(struct stat));
       if (lstat(subPath->getFullPath().c_str(), &info) == 0) {
@@ -553,7 +550,7 @@ PlatformResult Node::removeAsDirectory(const PathPtr& path, bool recursive) {
           platform_result = removeAsFile(subPath);
         }
         if (platform_result.error_code() != ErrorCode::NO_ERROR) {
-          LoggerE("Fail: getFullPath() (%d)", platform_result.error_code());
+          LoggerE("Fail: getFullPath() (%d)", static_cast<int>(platform_result.error_code()));
           closedir(dir);
           return platform_result;
         }
index cf2260a..9689622 100644 (file)
@@ -125,8 +125,8 @@ PlatformResult UnZip::listEntries(unsigned long* decompressedSize,
                                 ("ret: %d", err));
     }
 
-    LoggerD("file: %s | unc size: %d | comp size: %d", filename_inzip, file_info.uncompressed_size,
-            file_info.compressed_size);
+    LoggerD("file: %s | unc size: %lu | comp size: %lu", filename_inzip,
+            file_info.uncompressed_size, file_info.compressed_size);
 
     ArchiveFileEntryPtr entry = ArchiveFileEntryPtr(new ArchiveFileEntry());
     entry->setName(filename_inzip);
@@ -444,7 +444,7 @@ PlatformResult UnZip::updateCallbackWithArchiveStatistics(ExtractAllProgressCall
           bytesToReadableString(astats.uncompressed_size).c_str());
 
   callback->setNumberOfFilesToExtract(astats.number_of_files);
-  LoggerD("Number entries to extract: files: %d folders: %d", astats.number_of_files,
+  LoggerD("Number entries to extract: files: %lu folders: %lu", astats.number_of_files,
           astats.number_of_folders);
 
   return PlatformResult(ErrorCode::NO_ERROR);
index fc4de3a..15b3370 100644 (file)
@@ -234,7 +234,7 @@ PlatformResult UnZipExtractRequest::getCurrentFileInfo() {
 
   m_output_filepath = removeDuplicatedSlashesFromPath(m_extract_path + "/" + file_path);
 
-  LoggerD("Packed: [%s], uncompressed_size: %d, will extract to: [%s]", m_filename_inzip,
+  LoggerD("Packed: [%s], uncompressed_size: %lu, will extract to: [%s]", m_filename_inzip,
           m_file_info.uncompressed_size, m_output_filepath.c_str());
 
   std::string path, name;
@@ -399,7 +399,7 @@ PlatformResult UnZipExtractRequest::handleFileEntry() {
 
   bool marked_as_finished = false;
 
-  LoggerD("Started extracting: [%s] uncompressed size: %d - %s", m_filename_inzip,
+  LoggerD("Started extracting: [%s] uncompressed size: %lu - %s", m_filename_inzip,
           m_file_info.uncompressed_size,
           bytesToReadableString(m_file_info.uncompressed_size).c_str());
 
index 583bfea..bbf823c 100644 (file)
@@ -152,7 +152,7 @@ PlatformResult ZipAddRequest::run() {
             bytesToReadableString(size).c_str());
   }
 
-  LoggerD("m_files_to_compress: %d", m_files_to_compress);
+  LoggerD("m_files_to_compress: %lu", m_files_to_compress);
   LoggerD("m_bytes_to_compress: %llu (%s)", m_bytes_to_compress,
           bytesToReadableString(m_bytes_to_compress).c_str());
 
@@ -347,7 +347,7 @@ PlatformResult ZipAddRequest::addToZipArchive(filesystem::NodePtr src_file_node)
   LoggerD("m_bytes_compressed:%llu / m_bytes_to_compress: %llu", m_bytes_compressed,
           m_bytes_to_compress);
 
-  LoggerD("m_files_compressed:%d / m_files_to_compress: %d", m_files_compressed,
+  LoggerD("m_files_compressed: %lu / m_files_to_compress: %lu", m_files_compressed,
           m_files_to_compress);
 
   if (src_file_node->getType() == filesystem::NT_FILE) {
@@ -411,7 +411,7 @@ PlatformResult ZipAddRequest::addToZipArchive(filesystem::NodePtr src_file_node)
 
       LoggerD(
           "Callculatting overall progress: %llu/%llu bytes; "
-          "%d/%d files; current file: [%s] progress: %d/%d bytes; ",
+          "%lu/%lu files; current file: [%s] progress: %d/%d 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);
 
@@ -421,7 +421,7 @@ PlatformResult ZipAddRequest::addToZipArchive(filesystem::NodePtr src_file_node)
                    static_cast<double>(m_bytes_to_compress + m_files_to_compress);
       }
 
-      LoggerD("Wrote: %s total progress: %.2f%% %d/%d files",
+      LoggerD("Wrote: %s total progress: %.2f%% %lu/%lu files",
               bytesToReadableString(size_read).c_str(), progress * 100.0, m_files_compressed,
               m_files_to_compress);
 
index 9ccacdc..5d586e6 100644 (file)
@@ -52,6 +52,7 @@
          'variables': {
             'packages': [
               'capi-network-bluetooth',
+              'capi-appfw-app-control',
               'capi-system-info',
               'libpcrecpp',
             ]
index 06a1f90..287015e 100644 (file)
@@ -112,12 +112,12 @@ void BluetoothHealthProfileHandler::OnConnected(int result, const char* remote_a
       response_obj.insert(std::make_pair(kId, picojson::value(app_id)));
       response_obj.insert(std::make_pair(kEvent, picojson::value(kOnConnect)));
 
-      picojson::value result = picojson::value(picojson::object());
+      picojson::value result_picojson = picojson::value(picojson::object());
 
       BluetoothHealthChannel::ToJson(channel, type, device_info, app_id,
-                                     &result.get<picojson::object>());
+                                     &result_picojson.get<picojson::object>());
 
-      ReportSuccess(result, response_obj);
+      ReportSuccess(result_picojson, response_obj);
       bt_adapter_free_device_info(device_info);
 
       object->instance_.FireEvent("BLUETOOTH_HEALTH_APPLICATION_CHANGED", response);
@@ -139,11 +139,11 @@ void BluetoothHealthProfileHandler::OnConnected(int result, const char* remote_a
         object->connected_channels_.insert(channel);
       }
 
-      picojson::value result = picojson::value(picojson::object());
+      picojson::value result_picojson = picojson::value(picojson::object());
 
-      BluetoothHealthChannel::ToJson(channel, type, &result.get<picojson::object>());
+      BluetoothHealthChannel::ToJson(channel, type, &result_picojson.get<picojson::object>());
 
-      ReportSuccess(result, response->get<picojson::object>());
+      ReportSuccess(result_picojson, response->get<picojson::object>());
     } else {
       LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR,
                                        "Failed to establish a connection with health profile"),
index 83dabfc..b2f0be3 100644 (file)
@@ -69,11 +69,11 @@ class HexData {
     common::tools::HexToBin(p_data, size, (unsigned char*)pointer(), length_);
   }
 
-  const char* const pointer() const {
+  const char* pointer() const {
     return pointer_.get();
   }
 
-  const int length() const {
+  int length() const {
     return length_;
   }
 
index 6f24178..1b0160b 100644 (file)
@@ -39,13 +39,13 @@ BookmarkExtension::BookmarkExtension() {
   SetExtraJSEntryPoints(entry_points);
 
   if (bp_bookmark_adaptor_initialize()) {
-    LOGGER(ERROR) << "Fail: Bookmark not supported";
+    LoggerE("Fail: Bookmark not supported");
   }
 }
 
 BookmarkExtension::~BookmarkExtension() {
   if (bp_bookmark_adaptor_deinitialize()) {
-    LOGGER(ERROR) << "Fail: Deinitialize Bookmark";
+    LoggerE("Fail: Deinitialize Bookmark");
   }
 }
 
index ef161c0..556274d 100644 (file)
@@ -598,7 +598,7 @@ PlatformResult Calendar::Find(const picojson::object& args, picojson::array& arr
           if ((status = ErrorChecker(error_code)).IsError()) return status;
         } else {
           return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid union type!",
-                                    ("Invalid union type: %d", calType));
+                                    ("Invalid union type: %d", static_cast<int>(calType)));
         }
       }
       intermediate_filters.pop_back();
index 9bba6c4..99109bc 100644 (file)
@@ -235,7 +235,7 @@ PlatformResult CalendarItem::Remove(int type, int id) {
 
   int ret = calendar_db_delete_record(view_uri.c_str(), id);
   if (CALENDAR_ERROR_NONE != ret) {
-    LOGE("Calendar record delete error");
+    LoggerE("Calendar record delete error");
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Record deletion error",
         ("calendar_db_delete_record error: %d (%s)", ret, get_error_message(ret)));
@@ -391,7 +391,7 @@ PlatformResult CalendarItem::SetInt(int type, calendar_record_h rec, const std::
 
 PlatformResult CalendarItem::SetInt(int type, calendar_record_h rec, const std::string& property,
                                     int value) {
-  ScopeLogger("set: %s" + property);
+  ScopeLogger("set: %s", property.c_str());
 
   unsigned int prop;
   PlatformResult status = GetPlatformProperty(type, property, &prop);
@@ -404,7 +404,7 @@ PlatformResult CalendarItem::SetInt(int type, calendar_record_h rec, const std::
 
 PlatformResult CalendarItem::GetInt(int type, calendar_record_h rec, const std::string& property,
                                     int* value) {
-  ScopeLogger("set: %s" + property);
+  ScopeLogger("set: %s", property.c_str());
 
   unsigned int prop;
   PlatformResult status = GetPlatformProperty(type, property, &prop);
@@ -548,7 +548,7 @@ PlatformResult CalendarItem::SetCaltime(calendar_record_h rec, unsigned int prop
 PlatformResult CalendarItem::GetCaltime(int type, calendar_record_h rec,
                                         const std::string& property, calendar_time_s* cal_time,
                                         bool throw_on_error) {
-  ScopeLogger("set: %s" + property);
+  ScopeLogger("set: %s", property.c_str());
 
   unsigned int prop;
   PlatformResult status = GetPlatformProperty(type, property, &prop);
@@ -595,7 +595,7 @@ PlatformResult CalendarItem::SetLli(calendar_record_h rec, unsigned int property
 
 PlatformResult CalendarItem::GetLli(int type, calendar_record_h rec, const std::string& property,
                                     long long int* lli) {
-  ScopeLogger("set: %s" + property);
+  ScopeLogger("set: %s", property.c_str());
 
   unsigned int prop;
   PlatformResult status = GetPlatformProperty(type, property, &prop);
@@ -622,7 +622,7 @@ PlatformResult CalendarItem::GetLli(calendar_record_h rec, unsigned int property
 }
 
 Date CalendarItem::DateFromJson(const picojson::object& in) {
-  ScopeLogger("json date " + picojson::value(in).serialize());
+  ScopeLogger("json date %s", picojson::value(in).serialize().c_str());
 
   Date date = {(long long int)common::FromJson<double>(in, "UTCTimestamp"),
                (int)common::FromJson<double>(in, "year"),
index 1606635..94a273d 100644 (file)
@@ -162,7 +162,7 @@ PlatformResult CalendarManager::GetCalendar(const JsonObject& args, JsonObject&
 
   if (type != calendar_type) {
     return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Calendar not found",
-                              ("Calendar type doesn't match requested type %s", type));
+                              ("Calendar type doesn't match requested type %d", type));
   }
 
   status = CalendarRecord::CalendarToJson(record_ptr.get(), &out);
index 936a10e..86d4d6f 100644 (file)
@@ -49,7 +49,7 @@ Proxy::Proxy(const std::string& proxy_path, const std::string& proxy_iface,
       m_signal_iface.c_str());
 
   const gchar* unique_name = g_dbus_connection_get_unique_name(m_conn.getDBus());
-  LoggerD("Generated unique name: %d", unique_name);
+  LoggerD("Generated unique name: %s", unique_name);
 
   // path and interface are not obligatory to receive, but
   // they should be set to send the signals.
index 90fd8a4..ff428ee 100644 (file)
@@ -64,7 +64,7 @@
           'variables': {
             'packages': [
               'capi-appfw-app-manager',
-              'capi-appfw-application',
+              'capi-appfw-app-common',
               'capi-appfw-package-manager',
               'storage',
               'security-privilege-manager',
index 0e15003..cf4fed8 100644 (file)
       'XW_Extension.cc',
     ],
     'cflags': [
-      '-std=c++0x',
       '-fPIC',
       '-fvisibility=hidden',
       '-Wall',
+      '-Werror',
+    ],
+    'cflags_c': [
+      '-std=c11',
+    ],
+    'cflags_cc': [
+      '-std=c++14',
     ],
     'libraries' : [
       '-L .',
index 22f7f43..5347760 100644 (file)
@@ -368,7 +368,7 @@ void ParsedInstance::HandleException(const PlatformException& ex) {
 }
 
 void ParsedInstance::HandleError(const PlatformResult& e) {
-  LoggerE("Error: %s", static_cast<int>(e.error_code()));
+  LoggerE("Error: %d", static_cast<int>(e.error_code()));
   picojson::value result = picojson::value(picojson::object());
   ReportError(e, &result.get<picojson::object>());
   SendSyncReply(result.serialize().c_str());
index a321cbc..fdb04f0 100644 (file)
@@ -42,7 +42,7 @@ Storage::Storage(int id, StorageType type, StorageState state, std::string const
         break;
       default:
         name_ = "unknown";
-        LoggerE("Unknown storage type: %d", type);
+        LoggerE("Unknown storage type: %d", static_cast<int>(type));
         break;
     }
     name_ += std::to_string(id);
@@ -92,7 +92,7 @@ std::string VirtualRoot::ToString(StorageType type) {
     case StorageType::kMmc:
       return "EXTERNAL";
     default:
-      LoggerE("Unknown storage type: %d", type);
+      LoggerE("Unknown storage type: %d", static_cast<int>(type));
       return "UNKNOWN";
   }
 }
@@ -107,7 +107,7 @@ std::string VirtualRoot::ToString(StorageState state) {
     case StorageState::kMounted:
       return "MOUNTED";
     default:
-      LoggerE("Unknown storage state: %d", state);
+      LoggerE("Unknown storage state: %d", static_cast<int>(state));
       return "UNKNOWN";
   }
 }
index c263ce3..0e91b13 100644 (file)
@@ -37,7 +37,7 @@ PlatformResult AttributeMatchFlagFromString(const std::string &str,
   } else if (str == "EXISTS") {
     *filter_match_flag = AttributeMatchFlag::kExists;
   } else {
-    LoggerE("Invalid attribute match string: %i", str.c_str());
+    LoggerE("Invalid attribute match string: %s", str.c_str());
     return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid attribute match string!");
   }
 
@@ -52,7 +52,7 @@ PlatformResult CompositeFilterTypeFromString(const std::string &str,
   } else if (str == "INTERSECTION") {
     *comp_filter_type = CompositeFilterType::kIntersection;
   } else {
-    LoggerE("Invalid composite type string: %i", str.c_str());
+    LoggerE("Invalid composite type string: %s", str.c_str());
 
     return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid composite type string!");
   }
index fd159bb..3410dd8 100644 (file)
@@ -231,20 +231,7 @@ namespace common {
 // basis
 class ScopeLogger {
  public:
-  ScopeLogger(const std::string& f, const std::string& m, int l, const std::string& ex = "")
-      : file_(f), method_(m), extra_(ex) {
-    LoggerD("%s: %s(%d) > Enter %s", file_.c_str(), method_.c_str(), l, extra_.c_str());
-  }
-
-  template <typename... Args>
-  ScopeLogger(const std::string& f, const std::string& m, int l, const std::string& ex,
-              Args... args)
-      : file_(f), method_(m), extra_(ex) {
-#ifdef TIZEN_DEBUG_ENABLE
-    __dlog_print(LOG_ID_MAIN, DLOG_DEBUG, LOGGER_TAG,
-                 ("%s: %s(%d) > %s: %s(%d) > Enter " + extra_).c_str(), __MODULE__, __func__,
-                 __LINE__, file_.c_str(), method_.c_str(), l, args...);
-#endif
+  ScopeLogger(const std::string& f, const std::string& m) : file_(f), method_(m) {
   }
 
   ~ScopeLogger() {
@@ -254,14 +241,19 @@ class ScopeLogger {
  private:
   std::string file_;
   std::string method_;
-  std::string extra_;
 };
 
 }  // common
 
-#define ScopeLogger(EX, args...)               \
-  const common::ScopeLogger __sl__ {           \
-    __MODULE__, __func__, __LINE__, EX, ##args \
-  }
+#ifdef TIZEN_DEBUG_ENABLE
+#define ScopeLogger(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...)
+#endif
 
 #endif  // COMMON_LOGGER_H_
index 728b63a..44ae543 100644 (file)
@@ -309,27 +309,33 @@ void copy(const std::string& s, Iter 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) {
-#define MAP(val, sym) \
-  case val:           \
-    copy(sym, oi);    \
-    break
-      MAP('"', "\\\"");
-      MAP('\\', "\\\\");
-      MAP('/', "\\/");
-      MAP('\b', "\\b");
-      MAP('\f', "\\f");
-      MAP('\n', "\\n");
-      MAP('\r', "\\r");
-      MAP('\t', "\\t");
-#undef MAP
+      case '"':
+        copy("\\\"", oi);
+        break;
+      case '\\':
+        copy("\\\\", oi);
+        break;
+      case '\x7f':
+        copy("\\u007f", oi);
+        break;
       default:
-        if ((unsigned char)*i < 0x20 || *i == 0x7f) {
-          char buf[7];
-          SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff);
-          copy(buf, buf + 6, oi);
+        if ((unsigned char)*i < 0x20) {
+          const char* u = u_map[(unsigned char)*i];
+          while (*u) {
+            *oi++ = *u++;
+          }
         } else {
           *oi++ = *i;
         }
index 554a6d0..f376528 100644 (file)
@@ -24,7 +24,7 @@ PlatformResult::PlatformResult(const ErrorCode& error_code, const std::string& m
   ScopeLogger();
 
   if (ErrorCode::NO_ERROR != error_code) {
-    LoggerE("PlatformResult: %d, message: %s", error_code, message.c_str());
+    LoggerE("PlatformResult: %d, message: %s", static_cast<int>(error_code), message.c_str());
   }
 }
 
index 27dcdec..17e8c4d 100644 (file)
@@ -62,7 +62,8 @@ void ReportError(const PlatformException& ex, picojson::object& out) {
 }
 
 void ReportError(const PlatformResult& error, picojson::object* out) {
-  LoggerE("PlatformResult: %d, message: %s", error.error_code(), error.message().c_str());
+  LoggerE("PlatformResult: %d, message: %s", static_cast<int>(error.error_code()),
+          error.message().c_str());
   out->insert(std::make_pair("status", picojson::value("error")));
   out->insert(std::make_pair("error", error.ToJSON()));
 }
index 447b171..012e921 100644 (file)
@@ -364,7 +364,7 @@ PlatformResult AddressBookFind(const JsonObject& args, JsonArray& array) {
 
   long address_book_id = common::stol(FromJson<std::string>(args, "addressBookId"));
 
-  LoggerD("Searching in address book: %d", address_book_id);
+  LoggerD("Searching in address book: %ld", address_book_id);
 
   ContactSearchEngine engine;
   if (!IsUnified(address_book_id)) {
index 2769e2c..cee971e 100644 (file)
@@ -671,7 +671,7 @@ PlatformResult ContactSearchEngine::GetContacts(Iterator begin, Iterator end,
     contacts_record_h record = nullptr;
     int error_code = contacts_db_get_record(_contacts_contact._uri, id, &record);
     if (CONTACTS_ERROR_NONE != error_code) {
-      LoggerE("Failed to get contact with ID: %d", id);
+      LoggerE("Failed to get contact with ID: %ld", static_cast<long>(id));
       continue;
     }
 
@@ -683,7 +683,7 @@ PlatformResult ContactSearchEngine::GetContacts(Iterator begin, Iterator end,
       error_code =
           contacts_record_get_int(record, _contacts_contact.address_book_id, &address_book_id);
       if (CONTACTS_ERROR_NONE != error_code) {
-        LoggerE("Failed to get address book ID of contact with ID: %d", id);
+        LoggerE("Failed to get address book ID of contact with ID: %ld", static_cast<long>(id));
         continue;
       }
 
index 52b6aa0..eeefc42 100644 (file)
@@ -1465,7 +1465,7 @@ PlatformResult ExportContactRelationshipToContactsRecord(contacts_record_h conta
   } else if (type == kContactRelationshipTypeCustom) {
     type_to_set = CONTACTS_RELATIONSHIP_TYPE_CUSTOM;
   } else {
-    type_to_set = CONTACTS_MESSENGER_TYPE_OTHER;
+    type_to_set = CONTACTS_RELATIONSHIP_TYPE_OTHER;
   }
 
   status = ContactUtil::SetIntInRecord(child_record, _contacts_relationship.type, type_to_set);
index 6722aa5..8a3de66 100644 (file)
@@ -251,13 +251,13 @@ static void changedContentV1Callback(media_content_error_e error, int pid,
   ScopeLogger("File change callback");
 
   if (error != MEDIA_CONTENT_ERROR_NONE) {
-    LOGGER(ERROR) << "Media content changed callback error: " << error;
+    LoggerE("Media content changed callback error: %d", (int)error);
     return;
   }
 
   if (update_item == MEDIA_ITEM_FILE) {
     if (!uuid) {
-      LOGGER(ERROR) << "Provided uuid is NULL, ignoring";
+      LoggerE("Provided uuid is NULL, ignoring");
       return;
     }
 
@@ -292,7 +292,7 @@ static void changedContentV1Callback(media_content_error_e error, int pid,
     obj["listenerId"] = cbData->args.get("listenerId");
     common::Instance::PostMessage(cbData->instance, result.serialize().c_str());
   } else {
-    LOGGER(DEBUG) << "Media item is not a file, skipping.";
+    LoggerD("Media item is not a file, skipping.");
     return;
   }
 }
@@ -306,13 +306,13 @@ static void changedContentV2Callback(media_content_error_e error, int pid,
   ScopeLogger("Directory change callback");
 
   if (error != MEDIA_CONTENT_ERROR_NONE) {
-    LOGGER(ERROR) << "Media content changed v2 callback error: " << error;
+    LoggerE("Media content changed v2 callback error: %d", (int)error);
     return;
   }
 
   if (update_item == MEDIA_ITEM_DIRECTORY) {
     if (!uuid) {
-      LOGGER(ERROR) << "Provided uuid is NULL, ignoring";
+      LoggerE("Provided uuid is NULL, ignoring");
       return;
     }
 
@@ -347,7 +347,7 @@ static void changedContentV2Callback(media_content_error_e error, int pid,
     obj["listenerId"] = cbData->args.get("listenerId");
     common::Instance::PostMessage(cbData->instance, result.serialize().c_str());
   } else {
-    LOGGER(DEBUG) << "Media item is not directory, skipping.";
+    LoggerD("Media item is not directory, skipping.");
     return;
   }
 }
index edd86d5..9c069ed 100644 (file)
@@ -92,7 +92,7 @@ void ContentToJson(media_info_h info, picojson::object& o) {
   ret = media_info_get_media_type(info, &type);
 
   if (ret != MEDIA_CONTENT_ERROR_NONE) {
-    LOGGER(ERROR) << "Get media type failed: " << ret;
+    LoggerE("Get media type failed: %d", ret);
     type = MEDIA_CONTENT_TYPE_OTHERS;
   }
 
@@ -767,7 +767,7 @@ void ContentManager::find(const std::shared_ptr<ReplyCallbackData>& user_data) {
     std::string query;
     picojson::object argsObject = JsonCast<picojson::object>(user_data->args);
     if (filterMechanism.BuildQuery(FromJson<picojson::object>(argsObject, "filter"), &query)) {
-      LOGGER(DEBUG) << "Filter query: " << query;
+      LoggerD("Filter query: %s", query.c_str());
       ret = media_filter_set_condition(filter, query.c_str(), MEDIA_CONTENT_COLLATE_DEFAULT);
       if (MEDIA_CONTENT_ERROR_NONE != ret) {
         LoggerE("Platform filter setting failed, error %d", ret);
@@ -958,7 +958,7 @@ void ContentManager::createPlaylist(std::string name,
   if (playlist != NULL) {
     int id, cnt;
     char* thumb_path = NULL;
-    char* name = NULL;
+    char* name_playlist = NULL;
     filter_h filter = NULL;
     if (media_playlist_get_playlist_id(playlist, &id) == MEDIA_CONTENT_ERROR_NONE) {
       o["id"] = picojson::value(std::to_string(id));
@@ -978,9 +978,9 @@ void ContentManager::createPlaylist(std::string name,
     } else {
       LoggerE("Invalid thumbnail path for playlist.");
     }
-    if (media_playlist_get_name(playlist, &name) == MEDIA_CONTENT_ERROR_NONE) {
-      o["name"] = picojson::value(std::string(name));
-      free(name);
+    if (media_playlist_get_name(playlist, &name_playlist) == MEDIA_CONTENT_ERROR_NONE) {
+      o["name"] = picojson::value(std::string(name_playlist));
+      free(name_playlist);
     } else {
       LoggerE("Invalid name for playlist.");
     }
@@ -1378,21 +1378,21 @@ int ContentManager::getLyrics(const picojson::value& args, picojson::object& res
   int ret = METADATA_EXTRACTOR_ERROR_NONE;
   const std::string& contentURI = args.get("contentURI").to_str();
   if (contentURI.empty()) {
-    LOGGER(ERROR) << "contentURI empty - skipping media extractor";
+    LoggerE("contentURI empty - skipping media extractor");
     return -1;
   }
 
   metadata_extractor_h extractor;
   ret = metadata_extractor_create(&extractor);
   if (METADATA_EXTRACTOR_ERROR_NONE != ret) {
-    LOGGER(ERROR) << "metadata_extractor_create failed, error: " << ret;
+    LoggerE("metadata_extractor_create failed, error: %d", ret);
   }
   std::unique_ptr<std::remove_pointer<metadata_extractor_h>::type, int (*)(metadata_extractor_h)>
       extractor_ptr(extractor, &metadata_extractor_destroy);  // automatically release the memory
 
   ret = metadata_extractor_set_path(extractor, contentURI.c_str());
   if (ret != METADATA_EXTRACTOR_ERROR_NONE) {
-    LOGGER(ERROR) << "metadata_extractor_set_path failed, error: " << ret;
+    LoggerE("metadata_extractor_set_path failed, error: %d", ret);
     return ret;
   }
   picojson::array timestamps;
@@ -1401,7 +1401,7 @@ int ContentManager::getLyrics(const picojson::value& args, picojson::object& res
 
   ret = metadata_extractor_get_metadata(extractor, METADATA_SYNCLYRICS_NUM, &strSyncTextNum);
   if (ret != METADATA_EXTRACTOR_ERROR_NONE) {
-    LOGGER(ERROR) << "Media extractor error " << ret;
+    LoggerE("Media extractor error %d", ret);
     return ret;
   }
 
@@ -1432,7 +1432,7 @@ int ContentManager::getLyrics(const picojson::value& args, picojson::object& res
     if (ret == METADATA_EXTRACTOR_ERROR_NONE) {
       result["type"] = picojson::value(std::string("UNSYNCHRONIZED"));
       if (nullptr == unSyncText) {
-        LOGGER(ERROR) << "Unsynchronized lyrics text is NULL";
+        LoggerE("Unsynchronized lyrics text is NULL");
       }
       texts.push_back(picojson::value(unSyncText ? unSyncText : ""));
       result["texts"] = picojson::value(texts);
index c92902d..94bf83b 100755 (executable)
  *    limitations under the License.
  */
 
-tizen.debug = extension;
-
-var JSON_ = xwalk.JSON;
 var validator_ = xwalk.utils.validator;
+var converter_ = xwalk.utils.converter;
 var types_ = validator_.Types;
+var type_ = xwalk.utils.type;
+var native_ = new xwalk.utils.NativeManager(extension);
 
-var callbackId = 0;
-var callbacks = {};
+var DATA_CONTROL_MANAGER_LISTENER_ID = 'DataControlManagerChangeCallback';
 
-extension.setMessageListener(function(json) {
-    var result = JSON_.parse(json);
-    var callback = callbacks[result['callbackId']];
-    setTimeout(function() {
-        callback(result);
-        delete callbacks[result['callbackId']];
-    }, 0);
-});
+var DataType = {
+    MAP: 'MAP',
+    SQL: 'SQL'
+};
 
-function nextCallbackId() {
-    return callbackId++;
-}
+var DataControlListenersManager = (function() {
+    function changeEvent(event) {
+        var successCallback;
 
-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 (DataType.SQL === event.type.substr(0, 3)) {
+            if (type_.isEmptyObject(this._SQLDataControlCbMap)) {
+                return;
+            }
+            for (var listenerId in this._SQLDataControlCbMap) {
+                if (this._SQLDataControlCbMap.hasOwnProperty(listenerId)) {
+                    if (
+                        this._SQLDataControlCbMap[listenerId].providerId ===
+                            event.providerId &&
+                        this._SQLDataControlCbMap[listenerId].dataId === event.dataId
+                    ) {
+                        successCallback = this._SQLDataControlCbMap[listenerId]
+                            .changeCallback;
+                        if (type_.isFunction(successCallback)) {
+                            successCallback(event.type, {
+                                columns: event.columns,
+                                values: event.values
+                            });
+                        }
+                    }
+                }
+            }
+        } else {
+            if (type_.isEmptyObject(this._MAPDataControlCbMap)) {
+                return;
+            }
+            for (var listenerId in this._MAPDataControlCbMap) {
+                if (this._MAPDataControlCbMap.hasOwnProperty(listenerId)) {
+                    if (
+                        this._MAPDataControlCbMap[listenerId].providerId ===
+                            event.providerId &&
+                        this._MAPDataControlCbMap[listenerId].dataId === event.dataId
+                    ) {
+                        successCallback = this._MAPDataControlCbMap[listenerId]
+                            .changeCallback;
+                        if (type_.isFunction(successCallback)) {
+                            successCallback(event.type, {
+                                columns: event.columns,
+                                values: event.values
+                            });
+                        }
+                    }
+                }
+            }
+        }
+    }
 
-    if (typeof result !== 'object') {
-        throw new WebAPIException(WebAPIException.UNKNOWN_ERR);
+    function _DataControlListenerManager() {
+        this._SQLDataControlCbMap = {};
+        this._MAPDataControlCbMap = {};
+        this.lastListenerId = 0;
+        this.changeEvent = changeEvent.bind(this);
     }
 
-    if (result['status'] == 'success') {
-        if (result['result']) {
-            return result['result'];
+    _DataControlListenerManager.prototype.addChangeListener = function(
+        type,
+        providerId,
+        dataId,
+        changeCallback,
+        errorCallback
+    ) {
+        var _realWatchId = 0;
+        if (DataType.SQL === type) {
+            for (var i in this._SQLDataControlCbMap) {
+                if (
+                    this._SQLDataControlCbMap.hasOwnProperty(i) &&
+                    this._SQLDataControlCbMap[i].providerId === providerId &&
+                    this._SQLDataControlCbMap[i].dataId === dataId
+                ) {
+                    _realWatchId = this._SQLDataControlCbMap[i].realWatchId;
+                }
+            }
+        } else {
+            for (var i in this._MAPDataControlCbMap) {
+                if (
+                    this._MAPDataControlCbMap.hasOwnProperty(i) &&
+                    this._MAPDataControlCbMap[i].providerId === providerId &&
+                    this._MAPDataControlCbMap[i].dataId === dataId
+                ) {
+                    _realWatchId = this._MAPDataControlCbMap[i].realWatchId;
+                }
+            }
+        }
+
+        if (!_realWatchId) {
+            var callback = function(result) {
+                if (native_.isFailure(result)) {
+                    native_.callIfPossible(errorCallback, native_.getErrorObject(result));
+                    return;
+                }
+            };
+            var result = native_.call(
+                'DataControlConsumerObject_addChangeListener',
+                {
+                    providerId: providerId,
+                    dataId: dataId,
+                    type: type
+                },
+                callback
+            );
+
+            if (native_.isFailure(result)) {
+                throw native_.getErrorObject(result);
+            } else {
+                result = native_.getResultObject(result);
+                _realWatchId = converter_.toLong(result.watchId, true);
+            }
+            if (
+                type_.isEmptyObject(this._SQLDataControlCbMap) &&
+                type_.isEmptyObject(this._MAPDataControlCbMap)
+            ) {
+                native_.addListener(DATA_CONTROL_MANAGER_LISTENER_ID, this.changeEvent);
+            }
         }
-        return true;
-    } else if (result['status'] == 'error') {
-        var err = result['error'];
-        if (err) {
-            throw new WebAPIException(err);
+
+        if (DataType.SQL === type) {
+            this._SQLDataControlCbMap[++this.lastListenerId] = {
+                providerId: providerId,
+                dataId: dataId,
+                changeCallback: changeCallback,
+                realWatchId: _realWatchId
+            };
+        } else {
+            this._MAPDataControlCbMap[++this.lastListenerId] = {
+                providerId: providerId,
+                dataId: dataId,
+                changeCallback: changeCallback,
+                realWatchId: _realWatchId
+            };
         }
-        return false;
-    }
-}
 
-function callNativeWithCallback(cmd, args, callback) {
-    if (callback) {
-        var id = nextCallbackId();
-        args['callbackId'] = id;
-        callbacks[id] = callback;
-    }
+        return this.lastListenerId;
+    };
 
-    return callNative(cmd, args);
-}
+    _DataControlListenerManager.prototype.removeChangeListener = function(
+        type,
+        providerId,
+        dataId,
+        listenerId
+    ) {
+        var _realWatchId = 0;
+        if (
+            DataType.SQL === type &&
+            !type_.isUndefined(this._SQLDataControlCbMap[listenerId])
+        ) {
+            _realWatchId = this._SQLDataControlCbMap[listenerId].realWatchId;
+            delete this._SQLDataControlCbMap[listenerId];
+            for (var i in this._SQLDataControlCbMap) {
+                if (
+                    this._SQLDataControlCbMap.hasOwnProperty(i) &&
+                    this._SQLDataControlCbMap[i].realWatchId === _realWatchId
+                ) {
+                    return;
+                }
+            }
+        } else if (
+            DataType.MAP === type &&
+            !type_.isUndefined(this._MAPDataControlCbMap[listenerId])
+        ) {
+            _realWatchId = this._MAPDataControlCbMap[listenerId].realWatchId;
+            delete this._MAPDataControlCbMap[listenerId];
+            for (var i in this._MAPDataControlCbMap) {
+                if (
+                    this._MAPDataControlCbMap.hasOwnProperty(i) &&
+                    this._MAPDataControlCbMap[i].realWatchId === _realWatchId
+                ) {
+                    return;
+                }
+            }
+        } else {
+            console.log('Type invalid or listener was not added');
+            return;
+        }
+
+        if (0 != _realWatchId) {
+            native_.call('DataControlConsumerObject_removeChangeListener', {
+                watchId: _realWatchId
+            });
+
+            if (
+                type_.isEmptyObject(this._SQLDataControlCbMap) &&
+                type_.isEmptyObject(this._MAPDataControlCbMap)
+            ) {
+                native_.removeListener(DATA_CONTROL_MANAGER_LISTENER_ID);
+            }
+        }
+    };
+
+    return _DataControlListenerManager;
+})();
+
+var listenersManager = new DataControlListenersManager();
 
 function SetReadOnlyProperty(obj, n, v) {
     Object.defineProperty(obj, n, { value: v, writable: false });
 }
 
-var DataType = {
-    MAP: 'MAP',
-    SQL: 'SQL'
-};
-
 function DataControlManager() {
     // constructor of DataControlManager
 }
@@ -90,19 +239,22 @@ var getDataControlConsumer = function(providerId, dataId, type) {
     var args = validator_.validateArgs(arguments, [
         { name: 'providerId', type: types_.STRING },
         { name: 'dataId', type: types_.STRING },
-        { name: 'type', type: types_.ENUM, values: ['MAP', 'SQL'] }
+        { name: 'type', type: types_.ENUM, values: [DataType.SQL, DataType.MAP] }
     ]);
 
     var returnObject = null;
-    if (type === 'SQL') {
+    if (DataType.SQL === type) {
         returnObject = new SQLDataControlConsumer();
-    } else if (type === 'MAP') {
+    } else if (DataType.MAP == type) {
         returnObject = new MappedDataControlConsumer();
     }
-    SetReadOnlyProperty(returnObject, 'type', args.type); // read only property
+
+    // read only property
+    SetReadOnlyProperty(returnObject, 'type', args.type);
     // read only property
     SetReadOnlyProperty(returnObject, 'providerId', args.providerId);
-    SetReadOnlyProperty(returnObject, 'dataId', args.dataId); // read only property
+    // read only property
+    SetReadOnlyProperty(returnObject, 'dataId', args.dataId);
 
     return returnObject;
 };
@@ -115,6 +267,49 @@ function DataControlConsumerObject() {
     // constructor of DataControlConsumerObject
 }
 
+DataControlConsumerObject.prototype.addChangeListener = function() {
+    var args = validator_.validateArgs(arguments, [
+        {
+            name: 'dataChangeCallback',
+            type: types_.FUNCTION,
+            optional: false,
+            nullable: false
+        },
+        { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
+    ]);
+
+    var type = DataType.SQL;
+    if (this instanceof MappedDataControlConsumer) {
+        type = DataType.MAP;
+    }
+
+    return listenersManager.addChangeListener(
+        type,
+        this.providerId,
+        this.dataId,
+        args.dataChangeCallback,
+        args.errorCallback
+    );
+};
+
+DataControlConsumerObject.prototype.removeChangeListener = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'watchId', type: types_.LONG }
+    ]);
+
+    var type = DataType.SQL;
+    if (this instanceof MappedDataControlConsumer) {
+        type = DataType.MAP;
+    }
+
+    listenersManager.removeChangeListener(
+        type,
+        this.providerId,
+        this.dataId,
+        args.watchId
+    );
+};
+
 function SQLDataControlConsumer() {
     // constructor of SQLDataControlConsumer
 }
@@ -122,7 +317,7 @@ function SQLDataControlConsumer() {
 SQLDataControlConsumer.prototype = new DataControlConsumerObject();
 SQLDataControlConsumer.prototype.constructor = SQLDataControlConsumer;
 
-SQLDataControlConsumer.prototype.insert = function(reqId, insertionData) {
+SQLDataControlConsumer.prototype.insert = function() {
     var args = validator_.validateArgs(arguments, [
         { name: 'reqId', type: types_.LONG },
         { name: 'insertionData', type: types_.DICTIONARY },
@@ -150,31 +345,30 @@ SQLDataControlConsumer.prototype.insert = function(reqId, insertionData) {
         reqId: args.reqId,
         insertionData: args.insertionData
     };
-    try {
-        var syncResult = callNativeWithCallback(
-            'SQLDataControlConsumer_insert',
-            nativeParam,
-            function(result) {
-                if (result.status == 'success') {
-                    if (args.successCallback) {
-                        args.successCallback(result['requestId'], result['result']);
-                    }
-                }
-                if (result.status == 'error') {
-                    if (args.errorCallback) {
-                        var err = result['result'];
-                        var e = new WebAPIException(err.name, err.message);
-                        args.errorCallback(result['requestId'], e);
-                    }
-                }
+
+    var syncResult = native_.call('SQLDataControlConsumer_insert', nativeParam, function(
+        result
+    ) {
+        if (result.status == 'success') {
+            if (args.successCallback) {
+                args.successCallback(result['requestId'], result['result']);
+            }
+        }
+        if (result.status == 'error') {
+            if (args.errorCallback) {
+                var err = result['result'];
+                var e = new WebAPIException(err.name, err.message);
+                args.errorCallback(result['requestId'], e);
             }
-        );
-    } catch (e) {
-        throw e;
+        }
+    });
+
+    if (native_.isFailure(syncResult)) {
+        throw native_.getErrorObject(syncResult);
     }
 };
 
-SQLDataControlConsumer.prototype.update = function(reqId, updateData, where) {
+SQLDataControlConsumer.prototype.update = function() {
     var args = validator_.validateArgs(arguments, [
         { name: 'reqId', type: types_.LONG },
         { name: 'updateData', type: types_.DICTIONARY },
@@ -195,31 +389,30 @@ SQLDataControlConsumer.prototype.update = function(reqId, updateData, where) {
         where: args.where,
         updateData: args.updateData
     };
-    try {
-        var syncResult = callNativeWithCallback(
-            'SQLDataControlConsumer_update',
-            nativeParam,
-            function(result) {
-                if (result.status == 'success') {
-                    if (args.successCallback) {
-                        args.successCallback(result['requestId']);
-                    }
-                }
-                if (result.status == 'error') {
-                    if (args.errorCallback) {
-                        var err = result['result'];
-                        var e = new WebAPIException(err.name, err.message);
-                        args.errorCallback(result['requestId'], e);
-                    }
-                }
+
+    var syncResult = native_.call('SQLDataControlConsumer_update', nativeParam, function(
+        result
+    ) {
+        if (result.status == 'success') {
+            if (args.successCallback) {
+                args.successCallback(result['requestId']);
             }
-        );
-    } catch (e) {
-        throw e;
+        }
+        if (result.status == 'error') {
+            if (args.errorCallback) {
+                var err = result['result'];
+                var e = new WebAPIException(err.name, err.message);
+                args.errorCallback(result['requestId'], e);
+            }
+        }
+    });
+
+    if (native_.isFailure(syncResult)) {
+        throw native_.getErrorObject(syncResult);
     }
 };
 
-SQLDataControlConsumer.prototype.remove = function(reqId, where) {
+SQLDataControlConsumer.prototype.remove = function() {
     var args = validator_.validateArgs(arguments, [
         { name: 'reqId', type: types_.LONG },
         { name: 'where', type: types_.STRING },
@@ -238,54 +431,38 @@ SQLDataControlConsumer.prototype.remove = function(reqId, where) {
         reqId: args.reqId,
         where: args.where
     };
-    try {
-        var syncResult = callNativeWithCallback(
-            'SQLDataControlConsumer_remove',
-            nativeParam,
-            function(result) {
-                if (result.status == 'success') {
-                    if (args.successCallback) {
-                        args.successCallback(result['requestId']);
-                    }
-                }
-                if (result.status == 'error') {
-                    if (args.errorCallback) {
-                        var err = result['result'];
-                        var e = new WebAPIException(err.name, err.message);
-                        args.errorCallback(result['requestId'], e);
-                    }
-                }
+
+    var syncResult = native_.call('SQLDataControlConsumer_remove', nativeParam, function(
+        result
+    ) {
+        if (result.status == 'success') {
+            if (args.successCallback) {
+                args.successCallback(result['requestId']);
             }
-        );
-    } catch (e) {
-        throw e;
+        }
+        if (result.status == 'error') {
+            if (args.errorCallback) {
+                var err = result['result'];
+                var e = new WebAPIException(err.name, err.message);
+                args.errorCallback(result['requestId'], e);
+            }
+        }
+    });
+
+    if (native_.isFailure(syncResult)) {
+        throw native_.getErrorObject(syncResult);
     }
 };
 
-SQLDataControlConsumer.prototype.select = function(
-    reqId,
-    columns,
-    where,
-    successCallback
-) {
+SQLDataControlConsumer.prototype.select = function() {
     var args = validator_.validateArgs(arguments, [
         { name: 'reqId', type: types_.LONG },
         { name: 'columns', type: types_.ARRAY },
         { name: 'where', type: types_.STRING },
         { name: 'successCallback', type: types_.FUNCTION },
-        {
-            name: 'errorCallback',
-            type: types_.FUNCTION,
-            optional: true,
-            nullable: true
-        },
+        { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
         { name: 'page', type: types_.LONG, optional: true, nullable: true },
-        {
-            name: 'maxNumberPerPage',
-            type: types_.LONG,
-            optional: true,
-            nullable: true
-        },
+        { name: 'maxNumberPerPage', type: types_.LONG, optional: true, nullable: true },
         { name: 'order', type: types_.STRING, optional: true, nullable: true }
     ]);
 
@@ -306,26 +483,23 @@ SQLDataControlConsumer.prototype.select = function(
         nativeParam['order'] = args.order;
     }
 
-    try {
-        var syncResult = callNativeWithCallback(
-            'SQLDataControlConsumer_select',
-            nativeParam,
-            function(result) {
-                if (result.status == 'success') {
-                    args.successCallback(result['result'], result['requestId']);
-                }
-                if (result.status == 'error') {
-                    if (args.errorCallback) {
-                        var err = result['result'];
-                        var e = new WebAPIException(err.name, err.message);
-                        args.errorCallback(result['requestId'], e);
-                    }
-                }
+    var syncResult = native_.call('SQLDataControlConsumer_select', nativeParam, function(
+        result
+    ) {
+        if (result.status == 'success') {
+            args.successCallback(result['result'], result['requestId']);
+        }
+        if (result.status == 'error') {
+            if (args.errorCallback) {
+                var err = result['result'];
+                var e = new WebAPIException(err.name, err.message);
+                args.errorCallback(result['requestId'], e);
             }
-        );
-        // if you need synchronous result from native function using 'syncResult'.
-    } catch (e) {
-        throw e;
+        }
+    });
+
+    if (native_.isFailure(syncResult)) {
+        throw native_.getErrorObject(syncResult);
     }
 };
 
@@ -336,7 +510,7 @@ function MappedDataControlConsumer() {
 MappedDataControlConsumer.prototype = new DataControlConsumerObject();
 MappedDataControlConsumer.prototype.constructor = MappedDataControlConsumer;
 
-MappedDataControlConsumer.prototype.addValue = function(reqId, key, value) {
+MappedDataControlConsumer.prototype.addValue = function() {
     var args = validator_.validateArgs(arguments, [
         { name: 'reqId', type: types_.LONG },
         { name: 'key', type: types_.STRING },
@@ -347,12 +521,7 @@ MappedDataControlConsumer.prototype.addValue = function(reqId, key, value) {
             optional: true,
             nullable: true
         },
-        {
-            name: 'errorCallback',
-            type: types_.FUNCTION,
-            optional: true,
-            nullable: true
-        }
+        { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
     ]);
 
     var nativeParam = {
@@ -362,36 +531,32 @@ MappedDataControlConsumer.prototype.addValue = function(reqId, key, value) {
         key: args.key,
         value: args.value
     };
-    try {
-        var syncResult = callNativeWithCallback(
-            'MappedDataControlConsumer_addValue',
-            nativeParam,
-            function(result) {
-                if (result.status == 'success') {
-                    if (args.successCallback) {
-                        args.successCallback(result['requestId']);
-                    }
+
+    var syncResult = native_.call(
+        'MappedDataControlConsumer_addValue',
+        nativeParam,
+        function(result) {
+            if (result.status == 'success') {
+                if (args.successCallback) {
+                    args.successCallback(result['requestId']);
                 }
-                if (result.status == 'error') {
-                    if (args.errorCallback) {
-                        var err = result['result'];
-                        var e = new WebAPIException(err.name, err.message);
-                        args.errorCallback(result['requestId'], e);
-                    }
+            }
+            if (result.status == 'error') {
+                if (args.errorCallback) {
+                    var err = result['result'];
+                    var e = new WebAPIException(err.name, err.message);
+                    args.errorCallback(result['requestId'], e);
                 }
             }
-        );
-    } catch (e) {
-        throw e;
+        }
+    );
+
+    if (native_.isFailure(syncResult)) {
+        throw native_.getErrorObject(syncResult);
     }
 };
 
-MappedDataControlConsumer.prototype.removeValue = function(
-    reqId,
-    key,
-    value,
-    successCallback
-) {
+MappedDataControlConsumer.prototype.removeValue = function() {
     var args = validator_.validateArgs(arguments, [
         { name: 'reqId', type: types_.LONG },
         { name: 'key', type: types_.STRING },
@@ -407,29 +572,30 @@ MappedDataControlConsumer.prototype.removeValue = function(
         key: args.key,
         value: args.value
     };
-    try {
-        var syncResult = callNativeWithCallback(
-            'MappedDataControlConsumer_removeValue',
-            nativeParam,
-            function(result) {
-                if (result.status == 'success') {
-                    args.successCallback(result['requestId']);
-                }
-                if (result.status == 'error') {
-                    if (args.errorCallback) {
-                        var err = result['result'];
-                        var e = new WebAPIException(err.name, err.message);
-                        args.errorCallback(result['requestId'], e);
-                    }
+
+    var syncResult = native_.call(
+        'MappedDataControlConsumer_removeValue',
+        nativeParam,
+        function(result) {
+            if (result.status == 'success') {
+                args.successCallback(result['requestId']);
+            }
+            if (result.status == 'error') {
+                if (args.errorCallback) {
+                    var err = result['result'];
+                    var e = new WebAPIException(err.name, err.message);
+                    args.errorCallback(result['requestId'], e);
                 }
             }
-        );
-    } catch (e) {
-        throw e;
+        }
+    );
+
+    if (native_.isFailure(syncResult)) {
+        throw native_.getErrorObject(syncResult);
     }
 };
 
-MappedDataControlConsumer.prototype.getValue = function(reqId, key, successCallback) {
+MappedDataControlConsumer.prototype.getValue = function() {
     var args = validator_.validateArgs(arguments, [
         { name: 'reqId', type: types_.LONG },
         { name: 'key', type: types_.STRING },
@@ -443,35 +609,30 @@ MappedDataControlConsumer.prototype.getValue = function(reqId, key, successCallb
         reqId: args.reqId,
         key: args.key
     };
-    try {
-        var syncResult = callNativeWithCallback(
-            'MappedDataControlConsumer_getValue',
-            nativeParam,
-            function(result) {
-                if (result.status == 'success') {
-                    args.successCallback(result['result'], result['requestId']);
-                }
-                if (result.status == 'error') {
-                    if (args.errorCallback) {
-                        var err = result['result'];
-                        var e = new WebAPIException(err.name, err.message);
-                        args.errorCallback(result['requestId'], e);
-                    }
+
+    var syncResult = native_.call(
+        'MappedDataControlConsumer_getValue',
+        nativeParam,
+        function(result) {
+            if (result.status == 'success') {
+                args.successCallback(result['result'], result['requestId']);
+            }
+            if (result.status == 'error') {
+                if (args.errorCallback) {
+                    var err = result['result'];
+                    var e = new WebAPIException(err.name, err.message);
+                    args.errorCallback(result['requestId'], e);
                 }
             }
-        );
-    } catch (e) {
-        throw e;
+        }
+    );
+
+    if (native_.isFailure(syncResult)) {
+        throw native_.getErrorObject(syncResult);
     }
 };
 
-MappedDataControlConsumer.prototype.updateValue = function(
-    reqId,
-    key,
-    oldValue,
-    newValue,
-    successCallback
-) {
+MappedDataControlConsumer.prototype.updateValue = function() {
     var args = validator_.validateArgs(arguments, [
         { name: 'reqId', type: types_.LONG },
         { name: 'key', type: types_.STRING },
@@ -489,25 +650,26 @@ MappedDataControlConsumer.prototype.updateValue = function(
         oldValue: args.oldValue,
         newValue: args.newValue
     };
-    try {
-        var syncResult = callNativeWithCallback(
-            'MappedDataControlConsumer_updateValue',
-            nativeParam,
-            function(result) {
-                if (result.status == 'success') {
-                    args.successCallback(result['requestId']);
-                }
-                if (result.status == 'error') {
-                    if (args.errorCallback) {
-                        var err = result['result'];
-                        var e = new WebAPIException(err.name, err.message);
-                        args.errorCallback(result['requestId'], e);
-                    }
+
+    var syncResult = native_.call(
+        'MappedDataControlConsumer_updateValue',
+        nativeParam,
+        function(result) {
+            if (result.status == 'success') {
+                args.successCallback(result['requestId']);
+            }
+            if (result.status == 'error') {
+                if (args.errorCallback) {
+                    var err = result['result'];
+                    var e = new WebAPIException(err.name, err.message);
+                    args.errorCallback(result['requestId'], e);
                 }
             }
-        );
-    } catch (e) {
-        throw e;
+        }
+    );
+
+    if (native_.isFailure(syncResult)) {
+        throw native_.getErrorObject(syncResult);
     }
 };
 
index 00a41e3..a0104d4 100644 (file)
@@ -20,8 +20,8 @@
 
 #include <algorithm>
 #include <functional>
+#include <limits>
 #include <map>
-#include <memory>
 #include <string>
 #include <vector>
 
@@ -38,7 +38,10 @@ namespace datacontrol {
 namespace {
 // The privileges that required in Datacontrol API
 const std::string kPrivilegeDatacontrol = "http://tizen.org/privilege/datacontrol.consumer";
-
+const std::string kPrivilegeDatasharing = "http://tizen.org/privilege/datasharing";
+const std::string kPrivilegeAppmanagerLaunch = "http://tizen.org/privilege/appmanager.launch";
+const std::string SQL = "SQL";
+const std::string MAP = "MAP";
 }  // namespace
 
 using common::InvalidValuesException;
@@ -47,10 +50,13 @@ using common::IOException;
 using common::SecurityException;
 using common::UnknownException;
 using common::NotFoundException;
+using common::AbortException;
 
 using common::ScopeExit;
 using common::operator+;
 
+using namespace common;
+
 struct DatacontrolInformation {
   int callbackId;
   int requestId;
@@ -59,6 +65,19 @@ struct DatacontrolInformation {
 
 static std::map<int, DatacontrolInformation*> IdMap;
 
+ReplyCallbackData::~ReplyCallbackData() {
+  ScopeLogger();
+  if (SQL == event_type) {
+    if (handle && DATA_CONTROL_ERROR_NONE != data_control_sql_destroy(handle)) {
+      LoggerE("Destroy SQL handle failed");
+    }
+  } else {
+    if (handle && DATA_CONTROL_ERROR_NONE != data_control_map_destroy(handle)) {
+      LoggerE("Destroy MAP handle failed");
+    }
+  }
+}
+
 DatacontrolInstance::DatacontrolInstance() {
   ScopeLogger();
   using std::placeholders::_1;
@@ -75,11 +94,27 @@ DatacontrolInstance::DatacontrolInstance() {
                 DataControlManagerGetdatacontrolconsumer);
   REGISTER_SYNC("SQLDataControlConsumer_insert", SQLDataControlConsumerInsert);
   REGISTER_SYNC("MappedDataControlConsumer_getValue", MappedDataControlConsumerGetvalue);
+  REGISTER_SYNC("DataControlConsumerObject_removeChangeListener", RemoveChangeListener);
 #undef REGISTER_SYNC
+#define REGISTER_ASYNC(c, x) \
+  RegisterSyncHandler(c, std::bind(&DatacontrolInstance::x, this, _1, _2));
+  REGISTER_ASYNC("DataControlConsumerObject_addChangeListener", AddChangeListener);
+#undef REGISTER_ASYNC
 }
 
 DatacontrolInstance::~DatacontrolInstance() {
   ScopeLogger();
+  for (auto& item : reply_map) {
+    int watch_id = item.first;
+    auto handle = item.second->handle;
+    LoggerD("Deleting callback number %d", item.first);
+    int result = ::data_control_remove_data_change_cb(handle, watch_id);
+    if (DATA_CONTROL_ERROR_NONE != result) {
+      LoggerE("RemoveChangeListener %d failed: %d (%s)", watch_id, result,
+              get_error_message(result));
+    }
+  }
+  reply_map.clear();
 }
 
 static void ReplyAsync(DatacontrolInstance* instance, int callbackId, bool isSuccess,
@@ -130,8 +165,9 @@ static bool SQLColumnValue(result_set_cursor cursor, int columnIndex, picojson::
     }
     case DATA_CONTROL_SQL_COLUMN_TYPE_TEXT: {
       int size = data_control_sql_get_column_item_size(cursor, columnIndex);
-      if (DATA_CONTROL_ERROR_NONE > size) {
-        LoggerE("Getting column item size is failed with error : %s", ::get_error_message(size));
+      if (DATA_CONTROL_ERROR_NONE > size || INT_MAX == size) {
+        LoggerE("Getting column item size is failed with error : %s",
+                (INT_MAX == size) ? "integer overflow" : ::get_error_message(size));
         return false;
       }
       char* buffer = new char[size + 1];
@@ -147,8 +183,9 @@ static bool SQLColumnValue(result_set_cursor cursor, int columnIndex, picojson::
     }
     case DATA_CONTROL_SQL_COLUMN_TYPE_BLOB: {
       int size = data_control_sql_get_column_item_size(cursor, columnIndex);
-      if (DATA_CONTROL_ERROR_NONE > size) {
-        LoggerE("Getting column item size is failed with error : %s", ::get_error_message(size));
+      if (DATA_CONTROL_ERROR_NONE > size || INT_MAX == size) {
+        LoggerE("Getting column item size is failed with error : %s",
+                (INT_MAX == size) ? "integer overflow" : ::get_error_message(size));
         return false;
       }
       char* buffer = new char[size + 1];
@@ -166,7 +203,7 @@ static bool SQLColumnValue(result_set_cursor cursor, int columnIndex, picojson::
       break;
     }
     default: {
-      LoggerE("%th column is undefined column type", columnIndex);
+      LoggerE("%d column is undefined column type", columnIndex);
       return false;
     }
   }
@@ -881,6 +918,269 @@ void DatacontrolInstance::MappedDataControlConsumerUpdatevalue(const picojson::v
   }
 }
 
+int DatacontrolInstance::CreateMAPHandle(const std::string& providerId, const std::string& dataId,
+                                         data_control_h* handle) {
+  ScopeLogger();
+  int result = DATA_CONTROL_ERROR_NONE;
+
+  result = ::data_control_map_create(handle);
+  RETURN_IF_FAIL(result, "Creating map data control handle is failed with error");
+
+  result = ::data_control_map_set_provider_id(*handle, providerId.c_str());
+  RETURN_IF_FAIL(result, "Setting provider id is failed with error");
+
+  result = ::data_control_map_set_data_id(*handle, dataId.c_str());
+  RETURN_IF_FAIL(result, "Setting data id is failed the error");
+
+  return result;
+}
+
+int DatacontrolInstance::CreateSQLHandle(const std::string& providerId, const std::string& dataId,
+                                         data_control_h* handle) {
+  ScopeLogger();
+  int result = DATA_CONTROL_ERROR_NONE;
+
+  result = ::data_control_sql_create(handle);
+  RETURN_IF_FAIL(result, "Creating sql data control handle is failed with error");
+
+  result = ::data_control_sql_set_provider_id(*handle, providerId.c_str());
+  RETURN_IF_FAIL(result, "Setting provider id is failed with error");
+
+  result = ::data_control_sql_set_data_id(*handle, dataId.c_str());
+  RETURN_IF_FAIL(result, "Setting data id is failed the error");
+
+  return result;
+}
+
+PlatformResult DatacontrolInstance::ChangeTypeToString(data_control_data_change_type_e type_e,
+                                                       std::string* type) {
+  ScopeLogger();
+
+  switch (type_e) {
+    case DATA_CONTROL_DATA_CHANGE_SQL_UPDATE:
+      *type = "SQL_UPDATE";
+      break;
+    case DATA_CONTROL_DATA_CHANGE_SQL_INSERT:
+      *type = "SQL_INSERT";
+      break;
+    case DATA_CONTROL_DATA_CHANGE_SQL_DELETE:
+      *type = "SQL_DELETE";
+      break;
+    case DATA_CONTROL_DATA_CHANGE_MAP_SET:
+      *type = "MAP_SET";
+      break;
+    case DATA_CONTROL_DATA_CHANGE_MAP_ADD:
+      *type = "MAP_ADD";
+      break;
+    case DATA_CONTROL_DATA_CHANGE_MAP_REMOVE:
+      *type = "MAP_REMOVE";
+      break;
+    default:
+      return LogAndCreateResult(ErrorCode::ABORT_ERR, "Undefined data change type");
+      break;
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+void DatacontrolInstance::callback(data_control_h provider, data_control_data_change_type_e type,
+                                   bundle* bundle_data, void* user_data) {
+  ScopeLogger();
+
+  auto data = static_cast<ReplyCallbackData*>(user_data);
+
+  char* provider_id = nullptr;
+  char* data_id = nullptr;
+  SCOPE_EXIT {
+    free(provider_id);
+    free(data_id);
+  };
+  int result = DATA_CONTROL_ERROR_NONE;
+
+  if (DATA_CONTROL_DATA_CHANGE_SQL_UPDATE == type || DATA_CONTROL_DATA_CHANGE_SQL_INSERT == type ||
+      DATA_CONTROL_DATA_CHANGE_SQL_DELETE == type) {
+    if (MAP == data->event_type) {
+      LoggerI("Callback registered for different type");
+      return;
+    }
+
+    result = data_control_sql_get_provider_id(provider, &provider_id);
+
+    if (DATA_CONTROL_ERROR_NONE == result) {
+      result = data_control_sql_get_data_id(provider, &data_id);
+    }
+  } else {
+    if (SQL == data->event_type) {
+      LoggerI("Callback registered for different type");
+      return;
+    }
+
+    result = data_control_map_get_provider_id(provider, &provider_id);
+
+    if (DATA_CONTROL_ERROR_NONE == result) {
+      result = data_control_map_get_data_id(provider, &data_id);
+    }
+  }
+
+  picojson::value event = picojson::value(picojson::object());
+  picojson::object& obj = event.get<picojson::object>();
+
+  if (DATA_CONTROL_ERROR_NONE != result) {
+    obj.insert(std::make_pair("callbackId", picojson::value(std::to_string(data->callbackId))));
+    // According to native documentation only IOError can be returned to webapi, other errors are
+    // handled earlier
+    LogAndReportError(PlatformResult(ErrorCode::IO_ERR, "Get callback data failed"), &obj);
+    Instance::PostMessage(data->_instance, event.serialize().c_str());
+    return;
+  }
+
+  std::string event_type = "";
+  PlatformResult status = ChangeTypeToString(type, &event_type);
+
+  if (status.IsError()) {
+    obj.insert(std::make_pair("callbackId", picojson::value(std::to_string(data->callbackId))));
+    LogAndReportError(status, &obj);
+    Instance::PostMessage(data->_instance, event.serialize().c_str());
+    return;
+  }
+
+  obj.insert(std::make_pair("type", picojson::value(event_type)));
+
+  obj.insert(std::make_pair("providerId", picojson::value(std::string(provider_id))));
+  obj.insert(std::make_pair("dataId", picojson::value(std::string(data_id))));
+
+  obj.insert(std::make_pair("columns", picojson::value(picojson::array())));
+  obj.insert(std::make_pair("values", picojson::value(picojson::array())));
+
+  bundle_foreach(
+      bundle_data,
+      [](const char* key, const int type, const bundle_keyval_t* kv, void* user_data) {
+        ScopeLogger();
+
+        picojson::object& row_data = *(static_cast<picojson::object*>(user_data));
+
+        void* basic_val = NULL;
+        size_t basic_size = 0;
+
+        LoggerD("Key:%s, Type:%d\n", key, type);
+        bundle_keyval_get_basic_val(const_cast<bundle_keyval_t*>(kv), &basic_val, &basic_size);
+
+        row_data["columns"].get<picojson::array>().push_back(picojson::value(std::string(key)));
+        row_data["values"].get<picojson::array>().push_back(
+            picojson::value(std::string(static_cast<char*>(basic_val))));
+      },
+      &obj);
+
+  obj.insert(std::make_pair("listenerId", picojson::value("DataControlManagerChangeCallback")));
+
+  Instance::PostMessage(data->_instance, event.serialize().c_str());
+}
+
+// result_callback method is used only for pass information to errorCallback if any error
+// occur while adding listener
+void DatacontrolInstance::result_callback(data_control_h provider, data_control_error_e result,
+                                          int callback_id, void* user_data) {
+  ScopeLogger();
+  if (DATA_CONTROL_ERROR_NONE != result) {
+    auto data = static_cast<ReplyCallbackData*>(user_data);
+    picojson::value event = picojson::value(picojson::object());
+    picojson::object& obj = event.get<picojson::object>();
+    obj.insert(std::make_pair("callbackId", picojson::value(std::to_string(data->callbackId))));
+    // According to native documentation only IOError can be returned to webapi, other errors are
+    // handled earlier
+    LogAndReportError(IOException("AddChangeListener failed"), obj);
+    Instance::PostMessage(data->_instance, event.serialize().c_str());
+    if (0 != callback_id) {
+      data->_instance->EraseMap(callback_id);
+    }
+  }
+}
+
+void DatacontrolInstance::AddChangeListener(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeDatasharing, &out);
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeAppmanagerLaunch, &out);
+
+  CHECK_EXIST(args, "providerId", out)
+  CHECK_EXIST(args, "dataId", out)
+  CHECK_EXIST(args, "type", out)
+  CHECK_EXIST(args, "callbackId", out)
+
+  const std::string& providerId = args.get("providerId").get<std::string>();
+  const std::string& dataId = args.get("dataId").get<std::string>();
+  const std::string& type = args.get("type").get<std::string>();
+  int callbackId = static_cast<int>(args.get("callbackId").get<double>());
+  int result = DATA_CONTROL_ERROR_NONE;
+  data_control_h handle = nullptr;
+
+  if (SQL == type) {
+    result = CreateSQLHandle(providerId, dataId, &handle);
+  } else {
+    result = CreateMAPHandle(providerId, dataId, &handle);
+  }
+
+  if (DATA_CONTROL_ERROR_NONE != result) {
+    LogAndReportError(ServiceNotAvailableException("AddChangeListener failed"), out,
+                      ("AddChangeListener failed: %d (%s)", result, get_error_message(result)));
+    return;
+  }
+
+  std::shared_ptr<ReplyCallbackData> user_data(new ReplyCallbackData());
+  user_data->_instance = this;
+  user_data->callbackId = callbackId;
+  user_data->event_type = type;
+  user_data->handle = handle;
+
+  int watch_id = 0;
+  result = ::data_control_add_data_change_cb(handle, callback, user_data.get(), result_callback,
+                                             user_data.get(), &watch_id);
+
+  if (DATA_CONTROL_ERROR_NONE != result) {
+    LogAndReportError(ServiceNotAvailableException("AddChangeListener failed"), out,
+                      ("AddChangeListener failed: %d (%s)", result, get_error_message(result)));
+    return;
+  }
+
+  reply_map.insert(std::pair<int, ReplyCallbackDataPtr>(watch_id, user_data));
+
+  picojson::value return_value = picojson::value(picojson::object());
+  picojson::object& return_value_obj = return_value.get<picojson::object>();
+
+  return_value_obj.insert(std::make_pair("watchId", picojson::value(std::to_string(watch_id))));
+  ReportSuccess(return_value, out);
+}
+
+void DatacontrolInstance::RemoveChangeListener(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeDatasharing, &out);
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeAppmanagerLaunch, &out);
+
+  CHECK_EXIST(args, "watchId", out)
+
+  int watch_id = static_cast<int>(args.get("watchId").get<double>());
+  if (reply_map.end() == reply_map.find(watch_id)) {
+    LogAndReportError(IOException("RemoveChangeListener failed"), out,
+                      ("RemoveChangeListener failed, watch_id: %d", watch_id));
+    return;
+  }
+  data_control_h handle = reply_map[watch_id]->handle;
+
+  int result = ::data_control_remove_data_change_cb(handle, watch_id);
+
+  if (DATA_CONTROL_ERROR_NONE != result) {
+    // According to native documentation only IOError can be returned to webapi, other errors are
+    // handled earlier
+    LogAndReportError(IOException("RemoveChangeListener failed"), out,
+                      ("RemoveChangeListener failed: %d (%s)", result, get_error_message(result)));
+    return;
+  }
+
+  reply_map.erase(watch_id);
+
+  ReportSuccess(out);
+}
+
 #undef CHECK_EXIST
 
 }  // namespace datacontrol
index eed2bce..2412774 100644 (file)
@@ -18,6 +18,8 @@
 #define DATACONTROL_DATACONTROL_INSTANCE_H_
 
 #include <data_control.h>
+#include <map>
+#include <memory>
 #include <string>
 
 #include "common/extension.h"
 namespace extension {
 namespace datacontrol {
 
+class DatacontrolInstance;
+
+struct ReplyCallbackData {
+  DatacontrolInstance* _instance;
+  int callbackId;
+  std::string event_type;
+  data_control_h handle;
+
+  ~ReplyCallbackData();
+};
+
+typedef std::shared_ptr<ReplyCallbackData> ReplyCallbackDataPtr;
+typedef std::map<int, ReplyCallbackDataPtr> ReplyCallbackDataMap;
+
 class DatacontrolInstance : public common::ParsedInstance {
  public:
   DatacontrolInstance();
@@ -36,6 +52,23 @@ class DatacontrolInstance : public common::ParsedInstance {
   int RunSQLDataControlJob(const std::string& providerId, const std::string& dataId, int callbackId,
                            int userRequestId, DataControlJob job);
 
+  int CreateMAPHandle(const std::string& providerId, const std::string& dataId,
+                      data_control_h* handle);
+
+  int CreateSQLHandle(const std::string& providerId, const std::string& dataId,
+                      data_control_h* handle);
+
+  void EraseMap(int watch_id) {
+    reply_map.erase(watch_id);
+  };
+
+  static void callback(data_control_h provider, data_control_data_change_type_e type,
+                       bundle* bundle_data, void* user_data);
+  static void result_callback(data_control_h provider, data_control_error_e result, int callback_id,
+                              void* user_data);
+  static common::PlatformResult ChangeTypeToString(data_control_data_change_type_e type_e,
+                                                   std::string* type);
+
  private:
   void DataControlManagerGetdatacontrolconsumer(const picojson::value& args, picojson::object& out);
   void SQLDataControlConsumerInsert(const picojson::value& args, picojson::object& out);
@@ -46,6 +79,10 @@ class DatacontrolInstance : public common::ParsedInstance {
   void MappedDataControlConsumerRemovevalue(const picojson::value& args, picojson::object& out);
   void MappedDataControlConsumerGetvalue(const picojson::value& args, picojson::object& out);
   void MappedDataControlConsumerUpdatevalue(const picojson::value& args, picojson::object& out);
+  void AddChangeListener(const picojson::value& args, picojson::object& out);
+  void RemoveChangeListener(const picojson::value& args, picojson::object& out);
+
+  ReplyCallbackDataMap reply_map;
 };
 
 }  // namespace datacontrol
index a1388d4..20536ea 100755 (executable)
  *    limitations under the License.
  */
 
-var JSON_ = xwalk.JSON;
 var privUtils_ = xwalk.utils;
 var validator_ = xwalk.utils.validator;
 var types_ = validator_.Types;
-var check_ = xwalk.utils.type;
 var converter_ = xwalk.utils.converter;
+var native_ = new xwalk.utils.NativeManager(extension);
 
-var callbackId = 0;
+var DOWNLOAD_MANAGER_LISTENER_ID = 'DownloadManagerListener';
+
+var downloadId = 0;
 var callbacks = {};
 var requests = {};
 
-extension.setMessageListener(function(json) {
-    var result = JSON_.parse(json);
-    var callback = callbacks[result.callbackId];
-    //privUtils_.log("PostMessage received: " + result.status);
+function DownloadManagerChangeCallback(result) {
+    var callback = callbacks[result.downloadId];
 
     if (!callback) {
-        privUtils_.log('Ignoring unknown callback: ' + result.callbackId);
+        privUtils_.log('Ignoring unknown callback: ' + result.downloadId);
         return;
     }
     setTimeout(function() {
@@ -39,65 +38,34 @@ extension.setMessageListener(function(json) {
             if (callback.onprogress) {
                 var receivedSize = result.receivedSize;
                 var totalSize = result.totalSize;
-                callback.onprogress(result.callbackId, receivedSize, totalSize);
+                callback.onprogress(result.downloadId, receivedSize, totalSize);
             }
         } else if (result.status == 'paused') {
             if (callback.onpaused) {
-                callback.onpaused(result.callbackId);
+                callback.onpaused(result.downloadId);
             }
         } else if (result.status == 'canceled') {
             if (callback.oncanceled) {
-                callback.oncanceled(result.callbackId);
+                callback.oncanceled(result.downloadId);
+                delete callbacks[result.downloadId];
             }
         } else if (result.status == 'completed') {
             if (callback.oncompleted) {
                 var fullPath = result.fullPath;
-                callback.oncompleted(result.callbackId, fullPath);
+                callback.oncompleted(result.downloadId, fullPath);
+                delete callbacks[result.downloadId];
             }
         } else if (result.status == 'error') {
             if (callback.onfailed) {
-                callback.onfailed(result.callbackId, new WebAPIException(result.error));
+                callback.onfailed(result.downloadId, new WebAPIException(result.error));
+                delete callbacks[result.downloadId];
             }
         }
     }, 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 (result.result) {
-            return result.result;
-        }
-        return true;
-    } else if (result.status == 'error') {
-        var err = result.error;
-        if (err) {
-            throw new WebAPIException(err);
-        }
-        return false;
-    }
-}
-
-function callNativeWithCallback(cmd, args, callback) {
-    if (callback) {
-        var id = nextCallbackId();
-        args.callbackId = id;
-        callbacks[id] = callback;
-    }
-
-    return callNative(cmd, args);
+function nextDownloadId() {
+    return ++downloadId;
 }
 
 function SetReadOnlyProperty(obj, n, v) {
@@ -213,25 +181,25 @@ DownloadManager.prototype.start = function() {
         fileName: args.downloadRequest.fileName,
         networkType: args.downloadRequest.networkType,
         httpHeader: args.downloadRequest.httpHeader,
-        callbackId: nextCallbackId()
+        downloadId: nextDownloadId()
     };
 
     if (args.downloadCallback) {
-        this.setListener(nativeParam.callbackId, args.downloadCallback);
+        this.setListener(nativeParam.downloadId, args.downloadCallback);
     }
 
-    try {
-        callNative('DownloadManager_start', nativeParam);
-    } catch (e) {
-        if ('NetworkError' === e.name) {
+    var result = native_.callSync('DownloadManager_start', nativeParam);
+
+    if (native_.isFailure(result)) {
+        if ('NetworkError' === result.error.name) {
             return -1;
         }
-        throw e;
+        throw native_.getErrorObject(result);
     }
 
-    requests[nativeParam.callbackId] = args.downloadRequest;
+    requests[nativeParam.downloadId] = args.downloadRequest;
 
-    return nativeParam.callbackId;
+    return nativeParam.downloadId;
 };
 
 DownloadManager.prototype.cancel = function() {
@@ -249,10 +217,10 @@ DownloadManager.prototype.cancel = function() {
             'the identifier does not match any download operation in progress'
         );
 
-    try {
-        callNative('DownloadManager_cancel', nativeParam);
-    } catch (e) {
-        throw e;
+    var result = native_.callSync('DownloadManager_cancel', nativeParam);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
     }
 };
 
@@ -271,10 +239,10 @@ DownloadManager.prototype.pause = function() {
             'the identifier does not match any download operation in progress'
         );
 
-    try {
-        callNative('DownloadManager_pause', nativeParam);
-    } catch (e) {
-        throw e;
+    var result = native_.callSync('DownloadManager_pause', nativeParam);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
     }
 };
 
@@ -293,10 +261,10 @@ DownloadManager.prototype.resume = function() {
             'the identifier does not match any download operation in progress'
         );
 
-    try {
-        callNative('DownloadManager_resume', nativeParam);
-    } catch (e) {
-        throw e;
+    var result = native_.callSync('DownloadManager_resume', nativeParam);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
     }
 };
 
@@ -315,10 +283,12 @@ DownloadManager.prototype.getState = function() {
             'the identifier does not match any download operation in progress'
         );
 
-    try {
-        return callNative('DownloadManager_getState', nativeParam);
-    } catch (e) {
-        throw e;
+    var result = native_.callSync('DownloadManager_getState', nativeParam);
+
+    if (native_.isSuccess(result)) {
+        return native_.getResultObject(result);
+    } else {
+        throw native_.getErrorObject(result);
     }
 };
 
@@ -351,10 +321,12 @@ DownloadManager.prototype.getMIMEType = function() {
             'the identifier does not match any download operation in progress'
         );
 
-    try {
-        return callNative('DownloadManager_getMIMEType', nativeParam);
-    } catch (e) {
-        throw e;
+    var result = native_.callSync('DownloadManager_getMIMEType', nativeParam);
+
+    if (native_.isSuccess(result)) {
+        return native_.getResultObject(result);
+    } else {
+        throw native_.getErrorObject(result);
     }
 };
 
@@ -368,6 +340,9 @@ DownloadManager.prototype.setListener = function() {
         }
     ]);
 
+    if (!native_.isListenerSet(DOWNLOAD_MANAGER_LISTENER_ID)) {
+        native_.addListener(DOWNLOAD_MANAGER_LISTENER_ID, DownloadManagerChangeCallback);
+    }
     callbacks[args.downloadId] = args.downloadCallback;
 };
 
index 33e2d7a..f33102c 100644 (file)
@@ -36,6 +36,7 @@ std::mutex DownloadInstance::instances_mutex_;
 namespace {
 // The privileges that required in Download API
 const std::string kPrivilegeDownload = "http://tizen.org/privilege/download";
+const std::string kDownloadManagerListenerId = "DownloadManagerListener";
 
 }  // namespace
 
@@ -45,8 +46,6 @@ DownloadInstance::DownloadInstance() {
   using std::placeholders::_2;
 #define REGISTER_SYNC(c, x) RegisterSyncHandler(c, std::bind(&DownloadInstance::x, this, _1, _2));
   REGISTER_SYNC("DownloadManager_pause", DownloadManagerPause);
-  REGISTER_SYNC("DownloadManager_getDownloadRequest", DownloadManagerGetdownloadrequest);
-  REGISTER_SYNC("DownloadManager_setListener", DownloadManagerSetlistener);
   REGISTER_SYNC("DownloadManager_getMIMEType", DownloadManagerGetmimetype);
   REGISTER_SYNC("DownloadManager_start", DownloadManagerStart);
   REGISTER_SYNC("DownloadManager_cancel", DownloadManagerCancel);
@@ -61,35 +60,37 @@ DownloadInstance::DownloadInstance() {
 DownloadInstance::~DownloadInstance() {
   ScopeLogger();
   int ret;
+
+  std::lock_guard<std::mutex> lock(instances_mutex_);
+
   for (DownloadCallbackMap::iterator it = download_callbacks.begin();
        it != download_callbacks.end(); ++it) {
-    DownloadInfoPtr diPtr = it->second->instance->diMap[it->second->callbackId];
-    SLoggerD("~DownloadInstance() for callbackID %d Called", it->second->callbackId);
+    DownloadInfoPtr di_ptr = it->second->instance->di_map[it->second->download_id];
+    SLoggerD("~DownloadInstance() for callbackID %d Called", it->second->download_id);
 
-    if (diPtr) {
-      ret = download_unset_state_changed_cb(diPtr->download_id);
+    if (di_ptr) {
+      ret = download_unset_state_changed_cb(di_ptr->native_download_id);
       if (ret != DOWNLOAD_ERROR_NONE)
         LoggerE("download_unset_state_changed_cb() is failed. (%s)", get_error_message(ret));
 
-      ret = download_unset_progress_cb(diPtr->download_id);
+      ret = download_unset_progress_cb(di_ptr->native_download_id);
       if (ret != DOWNLOAD_ERROR_NONE)
         LoggerE("download_unset_progress_cb() is failed. (%s)", get_error_message(ret));
 
-      ret = download_cancel(diPtr->download_id);
+      ret = download_cancel(di_ptr->native_download_id);
       if (ret != DOWNLOAD_ERROR_NONE)
         LoggerE("download_cancel() is failed. (%s)", get_error_message(ret));
 
-      ret = download_destroy(diPtr->download_id);
+      ret = download_destroy(di_ptr->native_download_id);
       if (ret != DOWNLOAD_ERROR_NONE)
         LoggerE("download_destroy() is failed. (%s)", get_error_message(ret));
     } else {
-      LoggerD("diPtr is nullptr");
+      LoggerD("di_ptr is nullptr");
     }
 
     delete (it->second);
   }
 
-  std::lock_guard<std::mutex> lock(instances_mutex_);
   for (auto it = instances_.begin(); it != instances_.end(); it++) {
     if (*it == this) {
       instances_.erase(it);
@@ -185,19 +186,21 @@ common::PlatformResult DownloadInstance::convertError(int err, const std::string
 
 void DownloadInstance::OnStateChanged(int download_id, download_state_e state, void* user_data) {
   ScopeLogger();
-  CallbackPtr downCbPtr = static_cast<CallbackPtr>(user_data);
+  CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
 
   // Prevent to call finished, cancelled or failed function more than once
-  if (DOWNLOAD_STATE_COMPLETED == downCbPtr->state || DOWNLOAD_STATE_CANCELED == downCbPtr->state ||
-      DOWNLOAD_STATE_FAILED == downCbPtr->state) {
-    LoggerD("Already finished job, not calling callback for %d state", downCbPtr->state);
+  if (DOWNLOAD_STATE_COMPLETED == down_cb_ptr->state ||
+      DOWNLOAD_STATE_CANCELED == down_cb_ptr->state ||
+      DOWNLOAD_STATE_FAILED == down_cb_ptr->state) {
+    LoggerD("Already finished job, not calling callback for %d state", down_cb_ptr->state);
     return;
   }
 
-  downCbPtr->state = state;
-  downCbPtr->downloadId = download_id;
+  down_cb_ptr->state = state;
+  down_cb_ptr->native_download_id = download_id;
 
-  SLoggerD("State for callbackId %d changed to %d", downCbPtr->callbackId, static_cast<int>(state));
+  SLoggerD("State for callbackId %d changed to %d", down_cb_ptr->download_id,
+           static_cast<int>(state));
 
   switch (state) {
     case DOWNLOAD_STATE_NONE:
@@ -206,16 +209,16 @@ void DownloadInstance::OnStateChanged(int download_id, download_state_e state, v
       OnStart(download_id, user_data);
       break;
     case DOWNLOAD_STATE_PAUSED:
-      g_idle_add(OnPaused, downCbPtr);
+      g_idle_add(OnPaused, down_cb_ptr);
       break;
     case DOWNLOAD_STATE_COMPLETED:
-      g_idle_add(OnFinished, downCbPtr);
+      g_idle_add(OnFinished, down_cb_ptr);
       break;
     case DOWNLOAD_STATE_CANCELED:
-      g_idle_add(OnCanceled, downCbPtr);
+      g_idle_add(OnCanceled, down_cb_ptr);
       break;
     case DOWNLOAD_STATE_FAILED:
-      g_idle_add(OnFailed, downCbPtr);
+      g_idle_add(OnFailed, down_cb_ptr);
       break;
     default:
       LoggerD("Unexpected download state: %d", state);
@@ -225,29 +228,30 @@ void DownloadInstance::OnStateChanged(int download_id, download_state_e state, v
 
 gboolean DownloadInstance::OnProgressChanged(void* user_data) {
   ScopeLogger();
-  CallbackPtr downCbPtr = static_cast<CallbackPtr>(user_data);
+  CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
   std::lock_guard<std::mutex> lock(instances_mutex_);
-  if (!CheckInstance(downCbPtr->instance)) {
+  if (!CheckInstance(down_cb_ptr->instance)) {
     return FALSE;
   }
 
-  DownloadInfoPtr diPtr = downCbPtr->instance->diMap[downCbPtr->callbackId];
-  if (!diPtr) {
-    LoggerW("Download handle does not exist for callback id %d", downCbPtr->callbackId);
+  DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[down_cb_ptr->download_id];
+  if (!di_ptr) {
+    LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
     return FALSE;
   }
 
   picojson::value::object out;
   out["status"] = picojson::value("progress");
-  out["callbackId"] = picojson::value(static_cast<double>(downCbPtr->callbackId));
-  out["receivedSize"] = picojson::value(static_cast<double>(downCbPtr->received));
-  out["totalSize"] = picojson::value(static_cast<double>(diPtr->file_size));
+  out["downloadId"] = picojson::value(static_cast<double>(down_cb_ptr->download_id));
+  out["receivedSize"] = picojson::value(static_cast<double>(down_cb_ptr->received));
+  out["totalSize"] = picojson::value(static_cast<double>(di_ptr->file_size));
+  out["listenerId"] = picojson::value(kDownloadManagerListenerId);
 
-  LoggerD("OnProgressChanged for callbackId %d Called: Received: %ld", downCbPtr->callbackId,
-          downCbPtr->received);
+  LoggerD("OnProgressChanged for callbackId %d Called: Received: %llu", down_cb_ptr->download_id,
+          down_cb_ptr->received);
 
   picojson::value v = picojson::value(out);
-  Instance::PostMessage(downCbPtr->instance, v.serialize().c_str());
+  Instance::PostMessage(down_cb_ptr->instance, v.serialize().c_str());
 
   return FALSE;
 }
@@ -256,60 +260,60 @@ void DownloadInstance::OnStart(int download_id, void* user_data) {
   ScopeLogger();
   unsigned long long totalSize;
 
-  CallbackPtr downCbPtr = static_cast<CallbackPtr>(user_data);
+  CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
   std::lock_guard<std::mutex> lock(instances_mutex_);
-  if (!CheckInstance(downCbPtr->instance)) {
+  if (!CheckInstance(down_cb_ptr->instance)) {
     return;
   }
 
-  SLoggerD("OnStart for callbackId %d Called", downCbPtr->callbackId);
+  SLoggerD("OnStart for callbackId %d Called", down_cb_ptr->download_id);
 
-  DownloadInfoPtr diPtr = downCbPtr->instance->diMap[downCbPtr->callbackId];
-  if (!diPtr) {
-    LoggerW("Download handle does not exist for callback id %d", downCbPtr->callbackId);
+  DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[down_cb_ptr->download_id];
+  if (!di_ptr) {
+    LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
     return;
   }
 
   download_get_content_size(download_id, &totalSize);
 
-  diPtr->file_size = totalSize;
+  di_ptr->file_size = totalSize;
 }
 
 gboolean DownloadInstance::OnFinished(void* user_data) {
   ScopeLogger();
   char* fullPath = NULL;
 
-  CallbackPtr downCbPtr = static_cast<CallbackPtr>(user_data);
+  CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
   std::lock_guard<std::mutex> lock(instances_mutex_);
-  if (!CheckInstance(downCbPtr->instance)) {
+  if (!CheckInstance(down_cb_ptr->instance)) {
     return FALSE;
   }
 
-  int callback_id = downCbPtr->callbackId;
-  DownloadInfoPtr diPtr = downCbPtr->instance->diMap[callback_id];
-  if (!diPtr) {
-    LoggerW("Download handle does not exist for callback id %d", downCbPtr->callbackId);
+  int download_id = down_cb_ptr->download_id;
+  DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
+  if (!di_ptr) {
+    LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
     return FALSE;
   }
 
-  LoggerD("OnFinished for callbackID %d Called", callback_id);
+  LoggerD("OnFinished for callbackID %d Called", download_id);
 
   picojson::value::object out;
 
-  int ret = download_get_downloaded_file_path(downCbPtr->downloadId, &fullPath);
+  int ret = download_get_downloaded_file_path(down_cb_ptr->native_download_id, &fullPath);
   if (ret != DOWNLOAD_ERROR_NONE) {
     LogAndReportError(convertError(ret), &out, ("download_get_downloaded_file_path error: %d (%s)",
                                                 ret, get_error_message(ret)));
   } else {
-    ret = download_unset_state_changed_cb(diPtr->download_id);
+    ret = download_unset_state_changed_cb(di_ptr->native_download_id);
     if (ret != DOWNLOAD_ERROR_NONE) {
       LoggerW("%s", get_error_message(ret));
     }
-    ret = download_unset_progress_cb(diPtr->download_id);
+    ret = download_unset_progress_cb(di_ptr->native_download_id);
     if (ret != DOWNLOAD_ERROR_NONE) {
       LoggerW("%s", get_error_message(ret));
     }
-    ret = download_destroy(diPtr->download_id);
+    ret = download_destroy(di_ptr->native_download_id);
     if (ret != DOWNLOAD_ERROR_NONE) {
       LoggerW("%s", get_error_message(ret));
     }
@@ -317,10 +321,11 @@ gboolean DownloadInstance::OnFinished(void* user_data) {
     out["fullPath"] =
         picojson::value(common::FilesystemProvider::Create().GetVirtualPath(fullPath));
   }
-  out["callbackId"] = picojson::value(static_cast<double>(callback_id));
+  out["downloadId"] = picojson::value(static_cast<double>(download_id));
 
-  Instance::PostMessage(downCbPtr->instance, picojson::value(out).serialize().c_str());
-  // downCbPtr is freed in destructor, it prevent from crash if OnFinished state
+  out["listenerId"] = picojson::value(kDownloadManagerListenerId);
+  Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
+  // down_cb_ptr is freed in destructor, it prevent from crash if OnFinished state
   // was called after OnCanceled or OnFailed
   free(fullPath);
 
@@ -329,67 +334,69 @@ gboolean DownloadInstance::OnFinished(void* user_data) {
 
 gboolean DownloadInstance::OnPaused(void* user_data) {
   ScopeLogger();
-  CallbackPtr downCbPtr = static_cast<CallbackPtr>(user_data);
+  CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
   std::lock_guard<std::mutex> lock(instances_mutex_);
-  if (!CheckInstance(downCbPtr->instance)) {
+  if (!CheckInstance(down_cb_ptr->instance)) {
     return FALSE;
   }
 
-  int callback_id = downCbPtr->callbackId;
-  DownloadInfoPtr diPtr = downCbPtr->instance->diMap[callback_id];
-  if (!diPtr) {
-    LoggerW("Download handle does not exist for callback id %d", downCbPtr->callbackId);
+  int download_id = down_cb_ptr->download_id;
+  DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
+  if (!di_ptr) {
+    LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
     return FALSE;
   }
 
-  LoggerD("OnPaused for callbackID %d Called", callback_id);
+  LoggerD("OnPaused for callbackID %d Called", download_id);
 
   picojson::value::object out;
   out["status"] = picojson::value("paused");
-  out["callbackId"] = picojson::value(static_cast<double>(callback_id));
+  out["downloadId"] = picojson::value(static_cast<double>(download_id));
+  out["listenerId"] = picojson::value(kDownloadManagerListenerId);
 
-  Instance::PostMessage(downCbPtr->instance, picojson::value(out).serialize().c_str());
+  Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
   return FALSE;
 }
 
 gboolean DownloadInstance::OnCanceled(void* user_data) {
   ScopeLogger();
-  CallbackPtr downCbPtr = static_cast<CallbackPtr>(user_data);
+  CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
   std::lock_guard<std::mutex> lock(instances_mutex_);
-  if (!CheckInstance(downCbPtr->instance)) {
+  if (!CheckInstance(down_cb_ptr->instance)) {
     return FALSE;
   }
 
-  int callback_id = downCbPtr->callbackId;
-  DownloadInfoPtr diPtr = downCbPtr->instance->diMap[callback_id];
-  if (!diPtr) {
-    LoggerW("Download handle does not exist for callback id %d", callback_id);
+  int download_id = down_cb_ptr->download_id;
+  DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
+  if (!di_ptr) {
+    LoggerW("Download handle does not exist for callback id %d", download_id);
     return FALSE;
   }
 
-  LoggerD("OnCanceled for callbackID %d Called", callback_id);
+  LoggerD("OnCanceled for callbackID %d Called", download_id);
 
-  int ret = download_unset_state_changed_cb(diPtr->download_id);
+  int ret = download_unset_state_changed_cb(di_ptr->native_download_id);
   if (ret != DOWNLOAD_ERROR_NONE) {
     LoggerE("%s", get_error_message(ret));
   }
 
-  ret = download_unset_progress_cb(diPtr->download_id);
+  ret = download_unset_progress_cb(di_ptr->native_download_id);
   if (ret != DOWNLOAD_ERROR_NONE) {
     LoggerE("%s", get_error_message(ret));
   }
 
-  ret = download_destroy(diPtr->download_id);
+  ret = download_destroy(di_ptr->native_download_id);
   if (ret != DOWNLOAD_ERROR_NONE) {
     LoggerE("%s", get_error_message(ret));
   }
 
   picojson::value::object out;
   out["status"] = picojson::value("canceled");
-  out["callbackId"] = picojson::value(static_cast<double>(callback_id));
+  out["downloadId"] = picojson::value(static_cast<double>(download_id));
+  out["listenerId"] = picojson::value(kDownloadManagerListenerId);
 
-  Instance::PostMessage(downCbPtr->instance, picojson::value(out).serialize().c_str());
-  // downCbPtr is freed in destructor, it prevent from crash if OnFinished state
+  Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
+  // down_cb_ptr is freed in destructor, it prevent from crash if OnFinished state
   // was called after OnFinished or OnFailed
   return FALSE;
 }
@@ -399,25 +406,25 @@ gboolean DownloadInstance::OnFailed(void* user_data) {
   download_error_e error;
   picojson::object out;
 
-  CallbackPtr downCbPtr = static_cast<CallbackPtr>(user_data);
+  CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
   std::lock_guard<std::mutex> lock(instances_mutex_);
-  if (!CheckInstance(downCbPtr->instance)) {
+  if (!CheckInstance(down_cb_ptr->instance)) {
     return FALSE;
   }
 
-  int callback_id = downCbPtr->callbackId;
-  DownloadInfoPtr diPtr = downCbPtr->instance->diMap[callback_id];
-  if (!diPtr) {
-    LoggerW("Download handle does not exist for callback id %d", callback_id);
+  int download_id = down_cb_ptr->download_id;
+  DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
+  if (!di_ptr) {
+    LoggerW("Download handle does not exist for callback id %d", download_id);
     return FALSE;
   }
 
-  LoggerD("OnFailed for callbackID %d called", callback_id);
+  LoggerD("OnFailed for callbackID %d called", download_id);
 
-  download_get_error(downCbPtr->downloadId, &error);
+  download_get_error(down_cb_ptr->native_download_id, &error);
   if (DOWNLOAD_ERROR_NONE != error) {
     int http_status = 0;
-    int ret = download_get_http_status(downCbPtr->downloadId, &http_status);
+    int ret = download_get_http_status(down_cb_ptr->native_download_id, &http_status);
     std::string error_message;
     if (DOWNLOAD_ERROR_NONE != ret) {
       LoggerE("Gathering HTTP status failed, default error message will be used");
@@ -429,25 +436,26 @@ gboolean DownloadInstance::OnFailed(void* user_data) {
                       ("download_get_error error: %d (%s)", error, get_error_message(error)));
   }
 
-  int ret = download_unset_state_changed_cb(diPtr->download_id);
+  int ret = download_unset_state_changed_cb(di_ptr->native_download_id);
   if (ret != DOWNLOAD_ERROR_NONE) {
     LoggerE("%s", get_error_message(ret));
   }
 
-  ret = download_unset_progress_cb(diPtr->download_id);
+  ret = download_unset_progress_cb(di_ptr->native_download_id);
   if (ret != DOWNLOAD_ERROR_NONE) {
     LoggerE("%s", get_error_message(ret));
   }
 
-  ret = download_destroy(diPtr->download_id);
+  ret = download_destroy(di_ptr->native_download_id);
   if (DOWNLOAD_ERROR_NONE != ret) {
     LoggerE("%s", get_error_message(ret));
   }
 
-  out["callbackId"] = picojson::value(static_cast<double>(downCbPtr->callbackId));
+  out["downloadId"] = picojson::value(static_cast<double>(down_cb_ptr->download_id));
+  out["listenerId"] = picojson::value(kDownloadManagerListenerId);
 
-  Instance::PostMessage(downCbPtr->instance, picojson::value(out).serialize().c_str());
-  // downCbPtr is freed in destructor, it prevent from crash if OnFinished state
+  Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
+  // down_cb_ptr is freed in destructor, it prevent from crash if OnFinished state
   // was called after OnFinished or OnCanceled
   return FALSE;
 }
@@ -455,11 +463,11 @@ gboolean DownloadInstance::OnFailed(void* user_data) {
 void DownloadInstance::progress_changed_cb(int download_id, long long unsigned received,
                                            void* user_data) {
   ScopeLogger();
-  CallbackPtr downCbPtr = static_cast<CallbackPtr>(user_data);
-  downCbPtr->received = received;
-  downCbPtr->downloadId = download_id;
+  CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
+  down_cb_ptr->received = received;
+  down_cb_ptr->native_download_id = download_id;
 
-  g_idle_add(OnProgressChanged, downCbPtr);
+  g_idle_add(OnProgressChanged, down_cb_ptr);
 }
 
 #define CHECK_CONNECTION_ERROR(ret)                                                            \
@@ -544,14 +552,15 @@ common::PlatformResult DownloadInstance::CheckNetworkConnection(const std::strin
 void DownloadInstance::DownloadManagerStart(const picojson::value& args, picojson::object& out) {
   ScopeLogger();
   CHECK_PRIVILEGE_ACCESS(kPrivilegeDownload, &out);
-  CHECK_EXIST(args, "callbackId", out)
+  CHECK_EXIST(args, "downloadId", out)
   CHECK_EXIST(args, "url", out)
 
+  int ret;
   std::string network_type;
 
   DownloadInfoPtr di_ptr(new DownloadInfo);
 
-  di_ptr->callbackId = static_cast<int>(args.get("callbackId").get<double>());
+  di_ptr->download_id = static_cast<int>(args.get("downloadId").get<double>());
   di_ptr->url = args.get("url").is<std::string>() ? args.get("url").get<std::string>() : "";
 
   if (!args.get("destination").is<picojson::null>()) {
@@ -576,6 +585,7 @@ void DownloadInstance::DownloadManagerStart(const picojson::value& args, picojso
 
   bool network_support = false;
   bool network_available = false;
+
   common::PlatformResult result =
       CheckNetworkConnection(network_type, network_support, network_available, di_ptr);
   if (!result) {
@@ -584,7 +594,7 @@ void DownloadInstance::DownloadManagerStart(const picojson::value& args, picojso
   }
 
   /*
-   * There is no relevant feature for networkType == "ALL".
+   * There is no relevant feature for network_type == "ALL".
    */
   if (!network_support && ("ALL" != network_type)) {
     LogAndReportError(common::PlatformResult(common::ErrorCode::NOT_SUPPORTED_ERR,
@@ -604,38 +614,37 @@ void DownloadInstance::DownloadManagerStart(const picojson::value& args, picojso
     return;
   }
 
-  int ret;
-  CallbackPtr downCbPtr(new DownloadCallback);
+  CallbackPtr down_cb_ptr(new DownloadCallback);
 
-  downCbPtr->callbackId = di_ptr->callbackId;
-  downCbPtr->instance = this;
+  down_cb_ptr->download_id = di_ptr->download_id;
+  down_cb_ptr->instance = this;
 
-  download_callbacks[downCbPtr->callbackId] = downCbPtr;
+  download_callbacks[down_cb_ptr->download_id] = down_cb_ptr;
 
-  ret = download_create(&di_ptr->download_id);
+  ret = download_create(&di_ptr->native_download_id);
   if (ret != DOWNLOAD_ERROR_NONE) {
     LogAndReportError(convertError(ret), &out,
                       ("download_create error: %d (%s)", ret, get_error_message(ret)));
     return;
   }
 
-  ret = download_set_state_changed_cb(di_ptr->download_id, OnStateChanged,
-                                      static_cast<void*>(downCbPtr));
+  ret = download_set_state_changed_cb(di_ptr->native_download_id, OnStateChanged,
+                                      static_cast<void*>(down_cb_ptr));
   if (ret != DOWNLOAD_ERROR_NONE) {
     LogAndReportError(convertError(ret), &out, ("download_set_state_changed_cb error: %d (%s)", ret,
                                                 get_error_message(ret)));
     return;
   }
 
-  ret = download_set_progress_cb(di_ptr->download_id, progress_changed_cb,
-                                 static_cast<void*>(downCbPtr));
+  ret = download_set_progress_cb(di_ptr->native_download_id, progress_changed_cb,
+                                 static_cast<void*>(down_cb_ptr));
   if (ret != DOWNLOAD_ERROR_NONE) {
     LogAndReportError(convertError(ret), &out,
                       ("download_set_progress_cb error: %d (%s)", ret, get_error_message(ret)));
     return;
   }
 
-  ret = download_set_url(di_ptr->download_id, di_ptr->url.c_str());
+  ret = download_set_url(di_ptr->native_download_id, di_ptr->url.c_str());
   if (ret != DOWNLOAD_ERROR_NONE) {
     LogAndReportError(convertError(ret), &out,
                       ("download_set_url error: %d (%s)", ret, get_error_message(ret)));
@@ -643,7 +652,7 @@ void DownloadInstance::DownloadManagerStart(const picojson::value& args, picojso
   }
 
   if (di_ptr->destination.size() != 0) {
-    ret = download_set_destination(di_ptr->download_id, di_ptr->destination.c_str());
+    ret = download_set_destination(di_ptr->native_download_id, di_ptr->destination.c_str());
     if (ret != DOWNLOAD_ERROR_NONE) {
       LogAndReportError(convertError(ret), &out,
                         ("download_set_destination error: %d (%s)", ret, get_error_message(ret)));
@@ -652,7 +661,7 @@ void DownloadInstance::DownloadManagerStart(const picojson::value& args, picojso
   }
 
   if (!di_ptr->file_name.empty()) {
-    ret = download_set_file_name(di_ptr->download_id, di_ptr->file_name.c_str());
+    ret = download_set_file_name(di_ptr->native_download_id, di_ptr->file_name.c_str());
     if (ret != DOWNLOAD_ERROR_NONE) {
       LogAndReportError(convertError(ret), &out,
                         ("download_set_file_name error: %d (%s)", ret, get_error_message(ret)));
@@ -660,19 +669,19 @@ void DownloadInstance::DownloadManagerStart(const picojson::value& args, picojso
     }
   }
 
-  ret = download_set_network_type(di_ptr->download_id, di_ptr->network_type);
+  ret = download_set_network_type(di_ptr->native_download_id, di_ptr->network_type);
 
   if (args.get("httpHeader").is<picojson::object>()) {
     picojson::object obj = args.get("httpHeader").get<picojson::object>();
     for (picojson::object::const_iterator it = obj.begin(); it != obj.end(); ++it) {
-      download_add_http_header_field(di_ptr->download_id, it->first.c_str(),
+      download_add_http_header_field(di_ptr->native_download_id, it->first.c_str(),
                                      it->second.to_str().c_str());
     }
   }
 
-  diMap[downCbPtr->callbackId] = di_ptr;
+  di_map[down_cb_ptr->download_id] = di_ptr;
 
-  ret = download_start(di_ptr->download_id);
+  ret = download_start(di_ptr->native_download_id);
 
   if (ret == DOWNLOAD_ERROR_NONE) {
     ReportSuccess(out);
@@ -839,28 +848,16 @@ void DownloadInstance::DownloadManagerGetmimetype(const picojson::value& args,
   free(mimetype);
 }
 
-bool DownloadInstance::GetDownloadID(const int callback_id, int& download_id) {
+bool DownloadInstance::GetDownloadID(const int download_id, int& native_download_id) {
   ScopeLogger();
-  if (diMap.find(callback_id) != diMap.end()) {
-    download_id = diMap.find(callback_id)->second->download_id;
+  if (di_map.find(download_id) != di_map.end()) {
+    native_download_id = di_map.find(download_id)->second->native_download_id;
   } else {
     return false;
   }
   return true;
 }
 
-void DownloadInstance::DownloadManagerGetdownloadrequest(const picojson::value& args,
-                                                         picojson::object& out) {
-  ScopeLogger();
-  // Nothing to do
-}
-
-void DownloadInstance::DownloadManagerSetlistener(const picojson::value& args,
-                                                  picojson::object& out) {
-  ScopeLogger();
-  // Nothing to do
-}
-
 #undef CHECK_EXIST
 
 }  // namespace download
index 82ee99b..947e2ad 100644 (file)
@@ -46,20 +46,20 @@ class DownloadInstance : public common::ParsedInstance {
 
  private:
   struct DownloadInfo {
-    int callbackId;
+    int download_id;
     std::string url;
     std::string destination;
     std::string file_name;
     std::string http_header;
     download_network_type_e network_type;
 
-    int download_id;
+    int native_download_id;
     long long unsigned file_size;
   };
 
   struct DownloadCallback {
-    int callbackId;
-    int downloadId;
+    int download_id;
+    int native_download_id;
     DownloadInstance* instance;
     unsigned long long received;
     download_state_e state;
@@ -78,11 +78,9 @@ class DownloadInstance : public common::ParsedInstance {
   void DownloadManagerPause(const picojson::value& args, picojson::object& out);
   void DownloadManagerResume(const picojson::value& args, picojson::object& out);
   void DownloadManagerGetstate(const picojson::value& args, picojson::object& out);
-  void DownloadManagerGetdownloadrequest(const picojson::value& args, picojson::object& out);
   void DownloadManagerGetmimetype(const picojson::value& args, picojson::object& out);
-  void DownloadManagerSetlistener(const picojson::value& args, picojson::object& out);
 
-  bool GetDownloadID(const int callback_id, int& download_id);
+  bool GetDownloadID(const int download_id, int& native_download_id);
 
   static common::PlatformResult convertError(int err, const std::string& message = "");
   static void OnStateChanged(int download_id, download_state_e state, void* user_data);
@@ -100,7 +98,7 @@ class DownloadInstance : public common::ParsedInstance {
   static std::vector<DownloadInstance*> instances_;
 
   DownloadCallbackMap download_callbacks;
-  DownloadInfoMap diMap;
+  DownloadInfoMap di_map;
 };
 
 }  // namespace download
index 87c2b7b..9a07286 100644 (file)
@@ -456,7 +456,7 @@ void ExifInformation::unset(ExifInformationAttribute attribute) {
 }
 
 void ExifInformation::set(std::string attributeName, const picojson::value& v) {
-  ScopeLogger(attributeName);
+  ScopeLogger("%s", attributeName.c_str());
 
   switch (str2int(attributeName.c_str())) {
     case str2int(EI_URI): {
@@ -541,9 +541,11 @@ void ExifInformation::set(std::string attributeName, const picojson::value& v) {
   }
 }
 
-void ExifInformation::removeNulledAttributesFromExifData(ExifData* exif_data) {
+PlatformResult ExifInformation::removeNulledAttributesFromExifData(ExifData* exif_data) {
   ScopeLogger();
-  AssertMsg(exif_data, "exif_data is NULL");
+  if (!exif_data) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "exif_data is NULL");
+  }
 
   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) {
     LoggerD("Removing width");
@@ -637,6 +639,7 @@ void ExifInformation::removeNulledAttributesFromExifData(ExifData* exif_data) {
     ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF),
                                          exif_data);
   }
+  return PlatformResult(ErrorCode::NO_ERROR);
 }
 
 PlatformResult ExifInformation::updateAttributesInExifData(ExifData* exif_data) {
@@ -644,17 +647,19 @@ PlatformResult ExifInformation::updateAttributesInExifData(ExifData* exif_data)
 
   common::PlatformResult ret(common::ErrorCode::NO_ERROR);
 
-  AssertMsg(exif_data, "exif_data is NULL");
+  if (!exif_data) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "exif_data is NULL");
+  }
 
   if (isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) {
-    LoggerD("Saving width: %d", getWidth());
+    LoggerD("Saving width: %lu", getWidth());
     ret = ExifTagSaver::saveToExif(getWidth(), EXIF_TAG_IMAGE_WIDTH, exif_data);
     if (!ret) {
       return ret;
     }
   }
   if (isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) {
-    LoggerD("Saving height: %d", getHeight());
+    LoggerD("Saving height: %lu", getHeight());
     ret = ExifTagSaver::saveToExif(getHeight(), EXIF_TAG_IMAGE_LENGTH, exif_data);
     if (!ret) {
       return ret;
@@ -863,7 +868,11 @@ PlatformResult ExifInformation::saveToFile(const std::string& file_path) {
   // If we have created new ExifData there is nothing to remove
   if (!exif_data_is_new) {
     // Remove attributes that have been nulled
-    removeNulledAttributesFromExifData(exif_data);
+    PlatformResult ret = removeNulledAttributesFromExifData(exif_data);
+    if (ret.error_code() != ErrorCode::NO_ERROR) {
+      exif_data_unref(exif_data);
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Could not remove nulled attribute");
+    }
   }
   result = updateAttributesInExifData(exif_data);
   if (!result) {
index 01fadad..5ce3802 100644 (file)
@@ -204,7 +204,7 @@ class ExifInformation {
   void set(std::string attributeName, const picojson::value& args);
 
  private:
-  void removeNulledAttributesFromExifData(ExifData* exif_data);
+  common::PlatformResult removeNulledAttributesFromExifData(ExifData* exif_data);
   common::PlatformResult updateAttributesInExifData(ExifData* exif_data);
 
   std::string m_uri;
index 7ead390..0d91766 100644 (file)
@@ -28,10 +28,10 @@ namespace extension {
 namespace exif {
 
 void ExifTagSaver::removeExifEntryWithTag(const ExifTag tag, ExifData* exif_data) {
-  ScopeLogger("tag:%d (0x%x)", tag, 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, tag);
     return;
   }
 
@@ -319,7 +319,7 @@ common::PlatformResult ExifTagSaver::saveGpsLocationToExif(const ExifGPSLocation
 }
 
 ExifEntry* ExifTagSaver::prepareEntry(ExifData* exif_data, ExifTag tag) {
-  ScopeLogger("tag:%d (0x%x)", tag, exif_data);
+  ScopeLogger("tag: %d (%p)", tag, exif_data);
 
   ExifEntry* exif_entry = exif_data_get_entry(exif_data, tag);
   if (!exif_entry) {
index 6b13004..ebf2c0a 100644 (file)
@@ -332,7 +332,7 @@ size_t ExifUtil::getSizeOfExifFormatType(ExifFormat format) {
       break;
 
     default:
-      LoggerE("output ExifFormat: %d is not supported!");
+      LoggerE("output ExifFormat: %d is not supported!", format);
       return 0;
   }
 
index e80f8f0..a5e4e81 100644 (file)
@@ -42,9 +42,8 @@ Rational GetRationalFromEntry(ExifEntry* entry, ExifData* exif_data) {
   if (EXIF_FORMAT_RATIONAL == entry->format && entry->components >= 1 && entry->data) {
     const ExifByteOrder order = exif_data_get_byte_order(exif_data);
     return Rational(exif_get_rational(entry->data, order));
-  } else {
-    return Rational::createInvalid();
   }
+  return Rational::createInvalid();
 }
 
 bool GetRationalsFromEntry(ExifEntry* entry, ExifData* exif_data, unsigned long required_count,
@@ -60,9 +59,8 @@ bool GetRationalsFromEntry(ExifEntry* entry, ExifData* exif_data, unsigned long
     }
 
     return true;
-  } else {
-    return false;
   }
+  return false;
 }
 
 bool GetGCSPositionFromEntry(ExifEntry* entry, ExifData* exif_data, GCSPosition& out_pos) {
@@ -75,9 +73,8 @@ bool GetGCSPositionFromEntry(ExifEntry* entry, ExifData* exif_data, GCSPosition&
     out_pos.seconds =
         Rational(exif_get_rational(entry->data + 2 * ExifTypeInfo::RationalSize, order));
     return true;
-  } else {
-    return false;
   }
+  return false;
 }
 
 bool DecomposeExifUndefined(ExifEntry* entry, std::string& type, std::string& value) {
index a391e73..5fe598d 100644 (file)
@@ -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: %d bytes!", m_in_data_size, read_bytes));
+        ("Couldn't read all: %d bytes. Read only: %u 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:%d | Starting iteration: %d", offset, iterration);
+    LoggerD("offset:%u | Starting iteration: %u", 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:%d | Couldn't find marker! RAW DATA:{%s}", offset,
+                                ("offset:%u | 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:%d | Moved to section begin", offset);
+    LoggerD("offset:%u | Moved to section begin", offset);
 
     if (!isJpegMarker(section_begin[1])) {
       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "JPEG file is invalid",
-                                ("offset:%d | Is not valid marker: 0x%x RAW DATA:{%s}", offset,
+                                ("offset:%u | 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:%d | Found valid marker: 0x%x RAW DATA:{%s}", offset, cur_marker,
+    LoggerD("offset:%u | Found valid marker: 0x%x RAW DATA:{%s}", offset, 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:%d | Found: %s marker, moving to next marker at:%d", section_offset,
+      LoggerD("offset:%u | Found: %s marker, moving to next marker at:%u", section_offset,
               ((cur_marker == JPEG_MARKER_SOI) ? "SOI" : "EOI"), offset);
 
       if (cur_marker == JPEG_MARKER_EOI && m_padding_data != NULL) {
@@ -317,23 +317,24 @@ common::PlatformResult JpegFile::generateListOfSections() {
       // size 2 bytes
       const long section_data_len = total_section_len - 2;
 
-      LoggerD("offset:%d tag:0x%x | Read total_section_len:%d (data len:%d)", section_offset,
+      LoggerD("offset:%u tag:0x%x | Read total_section_len:%ld (data len:%ld)", section_offset,
               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:%d tag:0x%x | Error: total_section_len is: %d < 0",
+                                  ("offset:%u tag:0x%x | Error: total_section_len is: %ld < 0",
                                    offset, 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:%d tag:0x%x | Error: current section offset:%d"
-                                   " + 2 + total_section_len:%d = %d is greater then file size:%d",
-                                   offset, cur_marker, section_offset, total_section_len,
-                                   section_offset + 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,
+             section_offset + total_section_len, m_in_data_size));
       }
 
       if (JPEG_MARKER_APP1 == cur_marker) {
@@ -341,8 +342,8 @@ common::PlatformResult JpegFile::generateListOfSections() {
         section->exif_data = exif_data_new_from_data(section_begin, exif_data_size);
 
         LoggerD(
-            "offset:%d tag:0x%x | Loading exif from offset:%d"
-            " len:%d exif_data_new_from_data returned: %p",
+            "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);
 
         if (!section->exif_data) {
@@ -367,7 +368,7 @@ common::PlatformResult JpegFile::generateListOfSections() {
         std::size_t image_size = m_in_data_size - image_data_offset - 2;
         LoggerW(
             "offset:%d tag:0x%x"
-            " | Image data offset:%d Estimated image size:%d",
+            " | Image data offset:%u Estimated image size:%u",
             offset, cur_marker, image_data_offset, image_size);
 
         m_image_data = m_in_data + image_data_offset;
@@ -391,7 +392,7 @@ common::PlatformResult JpegFile::generateListOfSections() {
                 " delta:%d",
                 image_size, eoi_tag_index, image_size - eoi_tag_index);
 
-            LoggerW("Setting image_size to EOI tag: %d", eoi_tag_index);
+            LoggerW("Setting image_size to EOI tag: %u", eoi_tag_index);
             image_size = eoi_tag_index;
 
             m_padding_data = m_image_data + image_size + 2;  // (skip EOI tag)
@@ -404,10 +405,10 @@ common::PlatformResult JpegFile::generateListOfSections() {
         m_image_size = image_size;
 
         offset = image_data_offset + image_size;
-        LoggerD("offset:%d tag:0x%x | SOS Offset moved to next marker", offset, cur_marker);
+        LoggerD("offset:%u tag:0x%x | SOS Offset moved to next marker", offset, cur_marker);
       } else {
         offset += section_data_len;
-        LoggerD("offset:%d tag:0x%x | Offset moved to next marker", offset, cur_marker);
+        LoggerD("offset:%u tag:0x%x | Offset moved to next marker", offset, cur_marker);
       }
     }
   }
@@ -453,8 +454,9 @@ bool JpegFile::searchForTagInBuffer(const unsigned char* buffer_start,
 
 PlatformResult JpegFile::setNewExifData(ExifData* new_exif_data) {
   ScopeLogger();
-  AssertMsg(new_exif_data, "Trying to set NULL exif_data!");
-
+  if (!new_exif_data) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Pointer can not be null!");
+  }
   JpegFileSectionPtr exif = getExifSection();
   if (!exif) {
     LoggerW("Could't find Exif section - creating new one");
@@ -525,7 +527,7 @@ PlatformResult JpegFile::saveToFile(const std::string& out_path) {
 
   LoggerE(
       "Exception occured during saveToFilePriv "
-      "original file: [%] new: [%s]",
+      "original file: [%s] new: [%s]",
       m_source_file_path.c_str(), out_path.c_str());
 
   if (out_path == m_source_file_path) {
@@ -682,7 +684,7 @@ PlatformResult JpegFile::saveToFilePriv(const std::string& out_path) {
   }
 
   if (m_padding_data && m_padding_data_size > 0) {
-    LoggerD("Padding data exists and contains:%d bytes saving to JPEG file");
+    LoggerD("Padding data exists and contains:%d 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) {
@@ -723,7 +725,8 @@ JpegFileSectionPtr JpegFile::getExifSection() {
       } else {
         LoggerW(
             "Warning: found %d APP1/Exif sections -"
-            " only first is currently supported!");
+            " only first is currently supported!",
+            num_exif_sections);
       }
     }
   }
index fb0e446..987a61b 100644 (file)
@@ -44,7 +44,7 @@ Rational::Rational(const ExifRational& exif_rational)
 }
 
 Rational Rational::createFromDouble(const double value, const long precision) {
-  ScopeLogger("value:%f precision:%d", value, precision);
+  ScopeLogger("value: %f precision: %ld", value, precision);
   if (value < 0.0) {
     LoggerW("Trying to create negative Rational: %f!", value);
     return Rational();
@@ -125,7 +125,7 @@ Rational Rational::createFromDouble(const double value, const long precision) {
     result_denominator *= -1;
   }
 
-  LoggerD("Rational(%d, %d) error0 < error1m:%d", result_numerator, result_denominator,
+  LoggerD("Rational(%ld, %ld) error0 < error1m:%d", result_numerator, result_denominator,
           error0 < error1m);
 
   return Rational(numerator0, denominator0);
@@ -205,7 +205,7 @@ Rational Rational::createFromExposureTimeString(const std::string& exp_time) {
   }
 
   nominator += denominator * integer_value;
-  LoggerD("%d/%d -> %f", nominator, denominator, static_cast<float>(nominator) / denominator);
+  LoggerD("%ld/%ld -> %f", nominator, denominator, static_cast<float>(nominator) / denominator);
 
   if (0 == nominator) {
     // Exposure time = 0 is invalid value
index f7beef2..aad8b44 100644 (file)
@@ -137,26 +137,22 @@ void FilesystemInstance::FileRename(const picojson::value& args, picojson::objec
       std::bind(&FilesystemManager::Rename, &fsm, oldPath, newPath, onSuccess, onError));
 }
 
-/* str should be a reference to (possibly empty) std::string */
+/* Write to str buf bytes as if they were UTF-8 codepoints */
 static void encode_binary_in_string(const std::vector<std::uint8_t>& buf, std::string& str) {
   ScopeLogger();
   str.reserve(str.size() + buf.size());
 
   for (std::uint8_t byte : buf) {
-    if (byte >= 128) {
-      str += 0xC0 | (byte >> 6);
-      str += 0x80 | (byte & 0x3F);
-    } else if (byte > 0) {
+    if (byte < 128) {
       str += byte;
-    } else {
-      // zero as codepoint U+0100
-      str += 0xC4;
-      str += 0x80;
+      continue;
     }
+    str += 0xC0 | (byte >> 6);
+    str += 0x80 | (byte & 0x3F);
   }
 }
 
-/* buf should be a reference to (possibly empty) vector */
+/* Decode (max 2-byte) UTF-8 characters to buf, throws std::runtime_error */
 static void decode_binary_from_string(const std::string& str, std::vector<std::uint8_t>& buf) {
   ScopeLogger();
   buf.reserve(buf.size() + str.size());
@@ -169,12 +165,22 @@ static void decode_binary_from_string(const std::string& str, std::vector<std::u
       continue;
     }
     auto b1 = *it++;
+    if (it == end) {
+      throw std::runtime_error("internal error (invalid UTF-8 sequence)");
+    }
     auto b2 = *it++;
     unsigned int x = ((b1 & 0x1F) << 6) | (b2 & 0x3F);
-    buf.push_back(x != 0x100 ? x : 0);
+    buf.push_back(x);
   }
 }
 
+namespace latin1 {
+static auto to_utf8 = &encode_binary_in_string;
+/* It does not check if UTF-8 values are representable by ISO-8859-1. Make proper checks and
+ * substitute invalid characters in JavaScript before passing through crosswalk */
+static auto from_utf8 = &decode_binary_from_string;
+}
+
 static constexpr std::size_t NPOS = (std::size_t)(-1);
 /**
  * Returns a buffer. If length is NPOS, then it reads whole file, up to the end.
@@ -336,19 +342,25 @@ void FilesystemInstance::FileReadString(const picojson::value& args, picojson::o
   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
   CHECK_EXIST(args, "location", out)
   CHECK_EXIST(args, "offset", out)
-  CHECK_EXIST(args, "encoding", out)
 
   const std::string& location = args.get("location").get<std::string>();
   size_t offset = static_cast<size_t>(args.get("offset").get<double>());
   size_t length = args.contains("length") ? (size_t)args.get("length").get<double>() : NPOS;
+  const std::string& encoding =
+      args.contains("encoding") ? args.get("encoding").get<std::string>() : "utf-8";
 
   try {
-    std::vector<std::uint8_t> out_data = read_file(location, offset, length);
-    out_data.push_back('\0');
-    const char* str = (const char*)out_data.data();
+    std::vector<std::uint8_t> buf = read_file(location, offset, length);
 
-    // TODO: support iso-8859-1 (latin-1) encoding
-    ReportSuccess(picojson::value{str}, out);
+    if (encoding == "iso-8859-1") {
+      out["result"] = picojson::value(picojson::string_type, true);
+      latin1::to_utf8(buf, out["result"].get<std::string>());
+      ReportSuccess(out);
+    } else {  // default: UTF-8
+      buf.push_back('\0');
+      const char* str = (const char*)buf.data();
+      ReportSuccess(picojson::value{str}, out);
+    }
   } catch (std::runtime_error& e) {
     LoggerE("Cannot read file %s, cause: %s", location.c_str(), e.what());
     PrepareError(FilesystemError::Other, out);
@@ -385,15 +397,24 @@ void FilesystemInstance::FileWriteString(const picojson::value& args, picojson::
   CHECK_EXIST(args, "data", out)
   CHECK_EXIST(args, "offset", out)
   CHECK_EXIST(args, "rewrite", out)
-  CHECK_EXIST(args, "encoding", 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>());
+  const std::string& encoding =
+      args.contains("encoding") ? args.get("encoding").get<std::string>() : "utf-8";
 
   try {
-    write_file((const std::uint8_t*)str.c_str(), str.length(), location, offset, rewrite);
+    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);
+    } 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);
+    }
   } catch (std::runtime_error& e) {
     LoggerE("Cannot write to file %s, cause: %s", location.c_str(), e.what());
     PrepareError(FilesystemError::Other, out);
index 4a2186b..1de8ae8 100644 (file)
@@ -99,17 +99,17 @@ FilesystemError copyDirectory(const std::string& originPath, const std::string&
   SCOPE_EXIT {
     (void)closedir(dp);
   };
-  struct dirent entry;
-  struct dirent* result = nullptr;
-  while (0 == (status = readdir_r(dp, &entry, &result)) && result != nullptr) {
-    if (strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0) continue;
+  errno = 0;
+  struct dirent* entry = nullptr;
+  while (nullptr != (entry = readdir(dp))) {
+    if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
 
-    std::string oldLocation = originPath + std::string("/") + std::string(result->d_name);
-    std::string newLocation = destPath + std::string("/") + std::string(result->d_name);
+    std::string oldLocation = originPath + std::string("/") + std::string(entry->d_name);
+    std::string newLocation = destPath + std::string("/") + std::string(entry->d_name);
     FilesystemError fstatus = FilesystemError::None;
-    if (result->d_type == DT_DIR) {
+    if (entry->d_type == DT_DIR) {
       fstatus = copyDirectory(oldLocation, newLocation);
-    } else if (result->d_type == DT_REG) {
+    } else if (entry->d_type == DT_REG) {
       fstatus = copyFile(oldLocation, newLocation);
     }
     if (fstatus != FilesystemError::None) {
@@ -117,7 +117,8 @@ FilesystemError copyDirectory(const std::string& originPath, const std::string&
       return fstatus;
     }
   }
-  if (status != 0) {
+
+  if (0 != errno) {
     LoggerE("error occured");
     return FilesystemError::Other;
   }
@@ -288,7 +289,8 @@ void FilesystemManager::MakeDirectory(const std::string& path,
   result_cb(make_directory_worker(path));
 }
 
-void FilesystemManager::Rename(const std::string& oldPath, const std::string& newPath,
+// pass oldPath by copy to prevent possible TOCTOU bug
+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();
@@ -325,14 +327,20 @@ void FilesystemManager::Rename(const std::string& oldPath, const std::string& ne
     ret |= chown(newPath.c_str(), fileStat.st_uid, fileStat.st_gid);
     if (0 != ret) {
       LoggerE("Error while changing ownership/permissions [%s]", GetErrorString(errno).c_str());
-      remove(newPath.c_str());
+      if (0 != remove(newPath.c_str())) {
+        LoggerW("Error during rollback [%s], some of copied files may still exist",
+                GetErrorString(errno).c_str());
+      }
       error_cb(FilesystemError::Other);
       return;
     }
 
     if (0 != remove(oldPath.c_str())) {
       LoggerE("Error while removing file [%s]", GetErrorString(errno).c_str());
-      remove(newPath.c_str());
+      if (0 != remove(newPath.c_str())) {
+        LoggerW("Error during rollback [%s], some of copied files may still exist",
+                GetErrorString(errno).c_str());
+      }
       error_cb(FilesystemError::Other);
       return;
     }
@@ -348,18 +356,17 @@ void FilesystemManager::ReadDir(
 
   std::vector<std::string> fileList;
   DIR* dp = nullptr;
-  struct dirent entry;
-  struct dirent* result = nullptr;
-  int status = 0;
+  struct dirent* entry = nullptr;
 
   dp = opendir(path.c_str());
   if (dp != NULL) {
-    while ((status = readdir_r(dp, &entry, &result)) == 0 && result != nullptr) {
-      if (strcmp(result->d_name, ".") != 0 && strcmp(result->d_name, "..") != 0)
-        fileList.push_back(path + "/" + std::string(result->d_name));
+    errno = 0;
+    while (nullptr != (entry = readdir(dp))) {
+      if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
+        fileList.push_back(path + "/" + std::string(entry->d_name));
     }
     (void)closedir(dp);
-    if (status == 0) {
+    if (0 == errno) {
       success_cb(fileList);
     } else {
       LoggerE("error occured");
index d45aa12..ed237e6 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 84646a8..bb5bc89 100644 (file)
@@ -59,7 +59,8 @@ picojson::value FilesystemStat::toJSON() const {
   return retval;
 }
 
-FilesystemStat FilesystemStat::getStat(const std::string& path) {
+// pass path by copy to prevent possible TOCTOU bug
+FilesystemStat FilesystemStat::getStat(const std::string path) {
   ScopeLogger();
   struct stat aStatObj;
   FilesystemStat _result;
@@ -114,19 +115,18 @@ FilesystemStat FilesystemStat::getStat(const std::string& path) {
       (void)closedir(dir);
     };
 
-    struct dirent entry;
-    struct dirent* result = nullptr;
-    int status;
+    errno = 0;
+    struct dirent* entry = nullptr;
 
-    while ((0 == (status = readdir_r(dir, &entry, &result)) && result != nullptr)) {
-      std::string name = result->d_name;
+    while (nullptr != (entry = readdir(dir))) {
+      std::string name = entry->d_name;
       if (name == "." || name == "..") {
         continue;
       }
       _result.nlink++;
     }
 
-    if (status != 0) {
+    if (0 != errno) {
       LoggerE("Cannot count files in directory: %s", GetErrorString(errno).c_str());
       return _result;
     }
index a984ab1..31c5887 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 a81ead3..abc389d 100644 (file)
@@ -102,28 +102,21 @@ function _checkWriteAccess(mode) {
 }
 
 /* returns array of numbers */
-function string_to_binary(str) {
+function string_to_array(str) {
     var output = [];
     var len = str.length;
-    var c;
     for (var i = 0; i < len; i++) {
-        // decode unicode codepoint U+0100 as zero byte
-        c = str.charCodeAt(i);
-        output.push(c == 0x100 ? 0 : c);
+        output.push(str.charCodeAt(i));
     }
     return output;
 }
 
 /* receives array of numbers, returns string */
-function binary_to_string(data) {
+function array_to_string(data) {
     var output = '';
     var len = data.length;
-    // endecode zero byte as unicode codepoint U+0100
-    var zero = String.fromCharCode(0x100);
-    var b;
     for (var i = 0; i < len; i++) {
-        b = data[i] & 0xff; // conversion to octet
-        output += b == 0 ? zero : String.fromCharCode(b);
+        output += String.fromCharCode(data[i] & 0xff); // conversion to octet
     }
     return output;
 }
@@ -222,7 +215,7 @@ function readBytes() {
         throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Could not read');
     }
 
-    var decoded = string_to_binary(native_.getResultObject(result));
+    var decoded = string_to_array(native_.getResultObject(result));
 
     if (decoded.length) {
         can_change_size = true;
@@ -243,6 +236,18 @@ FileStream.prototype.readBase64 = function() {
     return base64_encode(readBytes.apply(this, arguments));
 };
 
+function check_characters_outside_latin1(str) {
+    var len = str.length;
+    for (var i = 0; i < len; ++i) {
+        if (str.charCodeAt(i) > 255) {
+            throw new WebAPIException(
+                WebAPIException.IO_ERR,
+                'Invalid character at ' + i + ': ' + str.charAt(i) + ' (not ISO-8859-1)'
+            );
+        }
+    }
+}
+
 function write() {
     var args = validator_.validateArgs(arguments, [
         {
@@ -269,6 +274,10 @@ function write() {
         rewrite: this._rewrite
     };
 
+    if (data.encoding == 'iso-8859-1') {
+        check_characters_outside_latin1(data.data);
+    }
+
     var result = native_.callSync('File_writeString', data);
 
     if (native_.isFailure(result)) {
@@ -289,8 +298,8 @@ function writeBytes() {
         {
             name: 'byteData',
             type: types_.ARRAY,
-            values: undefined /* was types_.OCTET, but checking moved
-                                to binary_to_string for performance */
+            values: undefined /* was types_.OCTET, but checking moved to
+                                array_to_string for performance */
         }
     ]);
 
@@ -307,7 +316,7 @@ function writeBytes() {
     var data = {
         location: commonFS_.toRealPath(this._file.fullPath),
         offset: this.position,
-        data: binary_to_string(args.byteData),
+        data: array_to_string(args.byteData),
         rewrite: this._rewrite
     };
 
diff --git a/src/humanactivitymonitor/gesture_manager.cc b/src/humanactivitymonitor/gesture_manager.cc
new file mode 100644 (file)
index 0000000..1168f4b
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2017 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 "humanactivitymonitor/gesture_manager.h"
+
+#include <gesture_recognition.h>
+
+#include "common/extension.h"
+#include "common/logger.h"
+#include "common/optional.h"
+#include "common/picojson.h"
+#include "common/scope_exit.h"
+#include "common/tools.h"
+
+namespace extension {
+namespace humanactivitymonitor {
+
+using common::PlatformResult;
+using common::ErrorCode;
+using common::tools::ReportError;
+using common::tools::ReportSuccess;
+
+namespace {
+
+const std::string kListenerId = "listenerId";
+const std::string kListener = "GestureRecognitionListener";
+const std::string kType = "type";
+const std::string kTimestamp = "timestamp";
+const std::string kAlwayOn = "alwaysOn";
+const std::string kAction = "action";
+const std::string kEvent = "event";
+const std::string kError = "error";
+const std::string kOnError = "onerror";
+const std::string kOnDetect = "ondetect";
+
+ErrorCode getErrorCode(int error) {
+  switch (error) {
+    case GESTURE_ERROR_NONE:
+      return ErrorCode::NO_ERROR;
+    case GESTURE_ERROR_INVALID_PARAMETER:
+      return ErrorCode::INVALID_VALUES_ERR;
+    case GESTURE_ERROR_OPERATION_FAILED:
+      return ErrorCode::IO_ERR;
+    case GESTURE_ERROR_NOT_SUPPORTED:
+      return ErrorCode::NOT_SUPPORTED_ERR;
+    case GESTURE_ERROR_INVALID_OPERATION:
+    case GESTURE_ERROR_OUT_OF_MEMORY:
+    case GESTURE_ERROR_PERMISSION_DENIED:
+    case GESTURE_ERROR_ALREADY_STARTED:
+    case GESTURE_ERROR_NOT_STARTED:
+    default:
+      return ErrorCode::ABORT_ERR;
+  }
+}
+
+PlatformResult StrToGestureType(const std::string& type, gesture_type_e* type_e) {
+  if ("GESTURE_DOUBLE_TAP" == type) {
+    *type_e = GESTURE_DOUBLE_TAP;
+  } else if ("GESTURE_MOVE_TO_EAR" == type) {
+    *type_e = GESTURE_MOVE_TO_EAR;
+  } else if ("GESTURE_NO_MOVE" == type) {
+    *type_e = GESTURE_NO_MOVE;
+  } else if ("GESTURE_PICK_UP" == type) {
+    *type_e = GESTURE_PICK_UP;
+  } else if ("GESTURE_SHAKE" == type) {
+    *type_e = GESTURE_SHAKE;
+  } else if ("GESTURE_SNAP" == type) {
+    *type_e = GESTURE_SNAP;
+  } else if ("GESTURE_TILT" == type) {
+    *type_e = GESTURE_TILT;
+  } else if ("GESTURE_TURN_FACE_DOWN" == type) {
+    *type_e = GESTURE_TURN_FACE_DOWN;
+  } else if ("GESTURE_WRIST_UP" == type) {
+    *type_e = GESTURE_WRIST_UP;
+  } else {
+    return PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unknown gesture type");
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+std::string GestureTypeToStr(gesture_type_e type) {
+  switch (type) {
+    case GESTURE_DOUBLE_TAP:
+      return "GESTURE_DOUBLE_TAP";
+    case GESTURE_MOVE_TO_EAR:
+      return "GESTURE_MOVE_TO_EAR";
+    case GESTURE_NO_MOVE:
+      return "GESTURE_NO_MOVE";
+    case GESTURE_PICK_UP:
+      return "GESTURE_PICK_UP";
+    case GESTURE_SHAKE:
+      return "GESTURE_SHAKE";
+    case GESTURE_SNAP:
+      return "GESTURE_SNAP";
+    case GESTURE_TILT:
+      return "GESTURE_TILT";
+    case GESTURE_TURN_FACE_DOWN:
+      return "GESTURE_TURN_FACE_DOWN";
+    case GESTURE_WRIST_UP:
+      return "GESTURE_WRIST_UP";
+    default:
+      return "GESTURE_UNKNOWN_TYPE";
+  }
+}
+std::string GestureEventToStr(gesture_event_e event, gesture_type_e gesture) {
+  switch (event) {
+    // GESTURE_EVENT_DETECTED == GESTURE_SHAKE_DETECTED == GESTURE_SNAP_X_NEGATIVE == 1
+    case GESTURE_EVENT_DETECTED:
+      if (GESTURE_SHAKE == gesture) {
+        return "GESTURE_SHAKE_DETECTED";
+      } else if (GESTURE_SNAP == gesture) {
+        return "GESTURE_SNAP_X_NEGATIVE";
+      } else {
+        return "GESTURE_EVENT_DETECTED";
+      }
+    // GESTURE_SHAKE_FINISHED == GESTURE_SNAP_X_POSITIVE == 2
+    case GESTURE_SHAKE_FINISHED:
+      if (GESTURE_SHAKE == gesture) {
+        return "GESTURE_SHAKE_FINISHED";
+      } else {
+        return "GESTURE_SNAP_X_POSITIVE";
+      }
+    case GESTURE_SNAP_Y_NEGATIVE:
+      return "GESTURE_SNAP_Y_NEGATIVE";
+    case GESTURE_SNAP_Y_POSITIVE:
+      return "GESTURE_SNAP_Y_POSITIVE";
+    case GESTURE_SNAP_Z_NEGATIVE:
+      return "GESTURE_SNAP_Z_NEGATIVE";
+    case GESTURE_SNAP_Z_POSITIVE:
+      return "GESTURE_SNAP_Z_POSITIVE";
+    default:
+      return "GESTURE_EVENT_NONE";
+  }
+}
+
+void GestureRecognitionDefaultCb(gesture_type_e gesture, const gesture_data_h data,
+                                 double timestamp, gesture_error_e error, void* user_data) {
+  ScopeLogger();
+
+  GestureManager* manager = static_cast<GestureManager*>(user_data);
+  if (!manager) {
+    LoggerW("User data is null");
+    return;
+  }
+
+  manager->CompleteGestureListenerCb(gesture, data, timestamp, error, false);
+}
+
+void GestureRecognitionAlwaysOnCb(gesture_type_e gesture, const gesture_data_h data,
+                                  double timestamp, gesture_error_e error, void* user_data) {
+  ScopeLogger();
+  GestureManager* manager = static_cast<GestureManager*>(user_data);
+
+  if (!manager) {
+    LoggerW("User data is null");
+    return;
+  }
+
+  manager->CompleteGestureListenerCb(gesture, data, timestamp, error, true);
+}
+
+}  // namespace
+
+GestureManager::GestureManager()
+    : m_callback(nullptr), m_recognition_default_map(), m_recognition_always_on_map() {
+  ScopeLogger();
+}
+
+GestureManager::~GestureManager() {
+  ScopeLogger();
+
+  int ret = GESTURE_ERROR_NONE;
+
+  for (auto& it : m_recognition_default_map) {
+    ret = gesture_stop_recognition(it.second);
+    if (GESTURE_ERROR_NONE != ret) {
+      LoggerE("gesture_stop_recognition() failed");
+    }
+
+    ret = gesture_release(it.second);
+    if (GESTURE_ERROR_NONE != ret) {
+      LoggerE("gesture_release() failed");
+    }
+  }
+
+  for (auto& it : m_recognition_always_on_map) {
+    ret = gesture_stop_recognition(it.second);
+    if (GESTURE_ERROR_NONE != ret) {
+      LoggerE("gesture_stop_recognition() failed");
+    }
+
+    ret = gesture_release(it.second);
+    if (GESTURE_ERROR_NONE != ret) {
+      LoggerE("gesture_release() failed");
+    }
+  }
+
+  m_recognition_default_map.clear();
+  m_recognition_always_on_map.clear();
+}
+
+PlatformResult GestureManager::IsSupported(const std::string& type, bool* is_supported) {
+  ScopeLogger();
+
+  gesture_type_e type_e = GESTURE_DOUBLE_TAP;
+  PlatformResult result = StrToGestureType(type, &type_e);
+  if (!result) {
+    return result;
+  }
+
+  int ret = gesture_is_supported(type_e, is_supported);
+  if (GESTURE_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        getErrorCode(ret), "Checking gesture failed",
+        ("Checking gesture failed, error: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+gesture_event_e GestureManager::GetGestureEvent(const gesture_data_h data) {
+  ScopeLogger();
+
+  gesture_event_e event = GESTURE_EVENT_NONE;
+  int ret = gesture_get_event(data, &event);
+  if (GESTURE_ERROR_NONE != ret) {
+    LoggerE("gesture_get_event() failed, error %d (%s)", ret, get_error_message(ret));
+  }
+
+  return event;
+}
+
+void GestureManager::FillTiltData(const gesture_data_h data, picojson::object* obj) {
+  ScopeLogger();
+
+  int x = 0;
+  int y = 0;
+
+  int ret = gesture_get_tilt(data, &x, &y);
+  if (GESTURE_ERROR_NONE != ret) {
+    LoggerE("gesture_get_tilt() failed, error %d (%s)", ret, get_error_message(ret));
+  }
+
+  obj->insert(std::make_pair("x", picojson::value(static_cast<double>(x))));
+  obj->insert(std::make_pair("y", picojson::value(static_cast<double>(y))));
+}
+
+void GestureManager::CompleteGestureListenerCb(gesture_type_e gesture, const gesture_data_h data,
+                                               double timestamp, gesture_error_e error,
+                                               bool always_on) {
+  ScopeLogger();
+
+  picojson::value response = picojson::value(picojson::object());
+  auto& obj = response.get<picojson::object>();
+
+  obj.insert(std::make_pair(kAlwayOn, picojson::value(always_on)));
+  obj.insert(std::make_pair(kListenerId, picojson::value(kListener)));
+
+  if (GESTURE_ERROR_NONE != error) {
+    obj.insert(std::make_pair(kAction, picojson::value(kOnError)));
+
+    PlatformResult result =
+        LogAndCreateResult(getErrorCode(error), "Error occurred during recognition");
+    ReportError(result, &obj);
+  } else {
+    gesture_event_e event = GetGestureEvent(data);
+    if (GESTURE_EVENT_NONE == event) {
+      LoggerD("Gesture event none detected.");
+      return;
+    }
+
+    std::string gesture_str = GestureTypeToStr(gesture);
+    if ("GESTURE_UNKNOWN_TYPE" == gesture_str) {
+      LoggerE("Unknown gesture type");
+      return;
+    }
+
+    obj.insert(std::make_pair(kAction, picojson::value(kOnDetect)));
+
+    picojson::value result = picojson::value(picojson::object());
+    auto& result_obj = result.get<picojson::object>();
+
+    result_obj.insert(std::make_pair(kEvent, picojson::value(GestureEventToStr(event, gesture))));
+    result_obj.insert(std::make_pair(kTimestamp, picojson::value(timestamp)));
+    result_obj.insert(std::make_pair(kType, picojson::value(gesture_str)));
+
+    if (GESTURE_TILT == gesture) {
+      FillTiltData(data, &result_obj);
+    }
+
+    ReportSuccess(result, obj);
+  }
+
+  if (!m_callback) {
+    LoggerE("Callback is not defined");
+  } else {
+    m_callback(&response);
+  }
+}
+
+PlatformResult GestureManager::AddListener(gesture_type_e type, gesture_option_e option,
+                                           RecognitionMap& gesture_map,
+                                           gesture_recognition_cb callback) {
+  ScopeLogger();
+
+  gesture_h handle = nullptr;
+
+  int ret = gesture_create(&handle);
+  if (GESTURE_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        getErrorCode(ret), "Creating handle failed",
+        ("Creating handle failed, error: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  ret = gesture_start_recognition(handle, type, option, callback, this);
+  if (GESTURE_ERROR_NONE != ret) {
+    gesture_release(handle);
+    return LogAndCreateResult(
+        getErrorCode(ret), "Starting recognition failed",
+        ("Starting recognition failed, error: %d (%s)", ret, get_error_message(ret)));
+  }
+
+  gesture_map[type] = handle;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult GestureManager::AddGestureRecognitionListener(const std::string& type,
+                                                             bool always_on, JsonCallback cb) {
+  ScopeLogger();
+
+  gesture_type_e type_e = GESTURE_DOUBLE_TAP;
+  PlatformResult result = StrToGestureType(type, &type_e);
+  if (!result) {
+    return result;
+  }
+
+  gesture_option_e option = GESTURE_OPTION_DEFAULT;
+  gesture_recognition_cb callback = GestureRecognitionDefaultCb;
+  RecognitionMap* gesture_map = &m_recognition_default_map;
+
+  if (!m_callback) {
+    m_callback = cb;
+  }
+
+  if (always_on) {
+    option = GESTURE_OPTION_ALWAYS_ON;
+    callback = GestureRecognitionAlwaysOnCb;
+    gesture_map = &m_recognition_always_on_map;
+  }
+
+  return AddListener(type_e, option, *gesture_map, callback);
+}
+
+PlatformResult GestureManager::RemoveGestureRecognitionListener(const std::string& type,
+                                                                bool always_on) {
+  ScopeLogger();
+
+  auto& recognition_map = always_on ? m_recognition_always_on_map : m_recognition_default_map;
+  gesture_type_e type_e = GESTURE_DOUBLE_TAP;
+  PlatformResult result = StrToGestureType(type, &type_e);
+  if (!result) {
+    LoggerD("Unknown gesture type.");
+    return PlatformResult(ErrorCode::NO_ERROR);
+  }
+
+  gesture_h handle = nullptr;
+  RecognitionMap::iterator it = recognition_map.find(type_e);
+
+  if (recognition_map.end() != it) {
+    handle = it->second;
+  }
+
+  if (handle) {
+    int ret = gesture_stop_recognition(handle);
+    if (GESTURE_ERROR_NONE != ret) {
+      return LogAndCreateResult(
+          getErrorCode(ret), "Stoping recognition failed",
+          ("Stoping recognition failed, error: %d (%s)", ret, get_error_message(ret)));
+    }
+
+    ret = gesture_release(handle);
+    if (GESTURE_ERROR_NONE != ret) {
+      LoggerE("gesture_release() failed");
+    }
+
+    recognition_map.erase(it);
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+}  // namespace humanactivitymonitor
+}  // namespace extension
diff --git a/src/humanactivitymonitor/gesture_manager.h b/src/humanactivitymonitor/gesture_manager.h
new file mode 100644 (file)
index 0000000..75b05f9
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017 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 HUMANACTIVITYMONITOR_GESTURE_MANAGER_H
+#define HUMANACTIVITYMONITOR_GESTURE_MANAGER_H
+
+#include <gesture_recognition.h>
+#include <functional>
+#include <string>
+
+#include "common/picojson.h"
+#include "common/platform_result.h"
+
+namespace extension {
+namespace humanactivitymonitor {
+
+using JsonCallback = std::function<void(picojson::value*)>;
+
+typedef std::map<gesture_type_e, gesture_h> RecognitionMap;
+
+class GestureManager {
+ public:
+  GestureManager();
+  virtual ~GestureManager();
+
+  common::PlatformResult IsSupported(const std::string& types, bool* is_supported);
+  common::PlatformResult AddGestureRecognitionListener(const std::string& type, bool always_on,
+                                                       JsonCallback cb);
+  common::PlatformResult RemoveGestureRecognitionListener(const std::string& type, bool always_on);
+  void CompleteGestureListenerCb(gesture_type_e gesture, const gesture_data_h data,
+                                 double timestamp, gesture_error_e error, bool always_on);
+
+ private:
+  gesture_event_e GetGestureEvent(const gesture_data_h data);
+  void FillTiltData(const gesture_data_h data, picojson::object* obj);
+  common::PlatformResult AddListener(gesture_type_e type, gesture_option_e option,
+                                     RecognitionMap& gesture_map, gesture_recognition_cb callback);
+
+  JsonCallback m_callback;
+  RecognitionMap m_recognition_default_map;
+  RecognitionMap m_recognition_always_on_map;
+};
+
+}  // namespace humanactivitymonitor
+}  // namespace extension
+
+#endif  // HUMANACTIVITYMONITOR_GESTURE_MANAGER_H
index 6c250c1..c6b54a0 100755 (executable)
@@ -17,6 +17,8 @@
         'humanactivitymonitor_instance.h',
         'humanactivitymonitor_manager.cc',
         'humanactivitymonitor_manager.h',
+        'gesture_manager.cc',
+        'gesture_manager.h',
       ],
       'conditions': [
         ['tizen == 1', {
index 50f7856..4f635f4 100755 (executable)
@@ -78,6 +78,18 @@ var SleepStatus = {
     AWAKE: 'AWAKE'
 };
 
+var GestureType = {
+    GESTURE_DOUBLE_TAP: 'GESTURE_DOUBLE_TAP',
+    GESTURE_MOVE_TO_EAR: 'GESTURE_MOVE_TO_EAR',
+    GESTURE_NO_MOVE: 'GESTURE_NO_MOVE',
+    GESTURE_PICK_UP: 'GESTURE_PICK_UP',
+    GESTURE_SHAKE: 'GESTURE_SHAKE',
+    GESTURE_SNAP: 'GESTURE_SNAP',
+    GESTURE_TILT: 'GESTURE_TILT',
+    GESTURE_TURN_FACE_DOWN: 'GESTURE_TURN_FACE_DOWN',
+    GESTURE_WRIST_UP: 'GESTURE_WRIST_UP'
+};
+
 function convertActivityData(type, data) {
     switch (type) {
     case HumanActivityType.PEDOMETER:
@@ -241,8 +253,8 @@ function startListener(listenerId, listener, method, data) {
         }
     }
 
-    // always set the listener, if it's another call to startListener()
-    // overwrite the old one
+    // always set the listener
+    //if it's another call to startListener() overwrite the old one
     native_.addListener(listenerId, listener);
 }
 
@@ -307,6 +319,14 @@ HumanActivityMonitorManager.prototype.start = function(type, changedCallback) {
         { name: 'options', type: types_.DICTIONARY, optional: true, nullable: true }
     ]);
 
+    if (HumanActivityType.WRIST_UP === args.type) {
+        utils_.warn(
+            'DEPRECATION WARNING: HumanActivityType.WRIST_UP is deprecated since ' +
+                'Tizen 4.0. Use GestureType and addGestureRecognitionListener to ' +
+                'monitor WRIST_UP gesture'
+        );
+    }
+
     var listenerId = 'HumanActivityMonitor_' + args.type;
     var optionsAttributes = ['callbackInterval', 'sampleInterval'],
         options = args.options || {};
@@ -391,6 +411,14 @@ HumanActivityMonitorManager.prototype.stop = function(type) {
         { name: 'type', type: types_.ENUM, values: Object.keys(HumanActivityType) }
     ]);
 
+    if (HumanActivityType.WRIST_UP === args.type) {
+        utils_.warn(
+            'DEPRECATION WARNING: HumanActivityType.WRIST_UP is deprecated since ' +
+                'Tizen 4.0. Use GestureType and addGestureRecognitionListener to ' +
+                'monitor WRIST_UP gesture'
+        );
+    }
+
     if (HumanActivityType.PEDOMETER === args.type) {
         stopListener(
             'HumanActivityMonitor_PEDOMETER',
@@ -589,6 +617,183 @@ HumanActivityMonitorManager.prototype.readRecorderData = function() {
     }
 };
 
+HumanActivityMonitorManager.prototype.isGestureSupported = function() {
+    var args = validator_.validateMethod(arguments, [
+        {
+            name: 'type',
+            type: types_.ENUM,
+            values: Object.keys(GestureType)
+        }
+    ]);
+
+    var callArgs = {};
+    callArgs.type = args.type;
+
+    var result = native_.callSync('GestureManager_isGestureSupported', callArgs);
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+
+    return native_.getResultObject(result);
+};
+
+function GestureListenerManager(native, listenerName) {
+    this.listeners = {};
+    //below maps keep information about number of registered listeners for the specific
+    //type there are two maps as one keeps information about listeners which should be
+    //always called and one keeps information about number of the listeners which should
+    //be called only if power-saving mode is off
+    this.typeCountMapDefault = {};
+    this.typeCountMapAlwaysOn = {};
+    this.nextId = 1;
+    this.nativeSet = false;
+    this.native = native;
+    this.listenerName = listenerName;
+    for (var type in GestureType) {
+        this.typeCountMapDefault[type] = this.typeCountMapAlwaysOn[type] = 0;
+    }
+}
+
+GestureListenerManager.prototype.onListenerCalled = function(msg) {
+    var d = undefined;
+    var result = undefined;
+    var alwaysOn = msg.alwaysOn;
+    switch (msg.action) {
+    case 'ondetect':
+        d = new GestureData(this.native.getResultObject(msg));
+        break;
+    case 'onerror':
+        d = this.native.getErrorObject(msg);
+        break;
+    default:
+        utils_.log('Unknown mode: ' + msg.action);
+        return;
+    }
+
+    for (var watchId in this.listeners) {
+        if (this.listeners.hasOwnProperty(watchId)) {
+            var listener = this.listeners[watchId];
+            var call = alwaysOn ? listener.alwaysOn : true;
+            if (call && listener[msg.action]) {
+                listener[msg.action](d);
+            }
+        }
+    }
+};
+
+GestureListenerManager.prototype.addListener = function(
+    successCb,
+    errorCb,
+    type,
+    alwaysOn
+) {
+    var listener = {
+        type: type,
+        alwaysOn: converter_.toBoolean(alwaysOn),
+        ondetect: successCb,
+        onerror: errorCb
+    };
+
+    var typeCountMap = alwaysOn ? this.typeCountMapAlwaysOn : this.typeCountMapDefault;
+    if (typeCountMap[type] === 0) {
+        var result = this.native.callSync(
+            'GestureManager_addGestureRecognitionListener',
+            listener
+        );
+        if (this.native.isFailure(result)) {
+            throw this.native.getErrorObject(result);
+        }
+    }
+
+    typeCountMap[type]++;
+    var id = this.nextId++;
+    this.listeners[id] = listener;
+
+    if (!this.nativeSet) {
+        this.native.addListener(this.listenerName, this.onListenerCalled.bind(this));
+        this.nativeSet = true;
+    }
+
+    return id;
+};
+
+GestureListenerManager.prototype.removeListener = function(watchId) {
+    if (this.listeners.hasOwnProperty(watchId)) {
+        var listener = this.listeners[watchId];
+        var typeCountMap = listener.alwaysOn
+            ? this.typeCountMapAlwaysOn
+            : this.typeCountMapDefault;
+
+        if (typeCountMap[listener.type] === 1) {
+            var result = this.native.callSync(
+                'GestureManager_removeGestureRecognitionListener',
+                listener
+            );
+            if (this.native.isFailure(result)) {
+                throw this.native.getErrorObject(result);
+            }
+        }
+
+        delete this.listeners[watchId];
+        typeCountMap[listener.type]--;
+    }
+
+    if (this.nativeSet && type_.isEmptyObject(this.listeners)) {
+        this.native.removeListener(this.listenerName);
+        this.nativeSet = false;
+    }
+};
+
+var GESTURE_RECOGNITION_LISTENER = 'GestureRecognitionListener';
+var gestureRecognitionListener = new GestureListenerManager(
+    native_,
+    GESTURE_RECOGNITION_LISTENER
+);
+
+HumanActivityMonitorManager.prototype.addGestureRecognitionListener = function() {
+    var args = validator_.validateMethod(arguments, [
+        {
+            name: 'type',
+            type: types_.ENUM,
+            values: Object.keys(GestureType)
+        },
+        {
+            name: 'eventCallback',
+            type: types_.FUNCTION
+        },
+        {
+            name: 'errorCallback',
+            type: types_.FUNCTION,
+            optional: true,
+            nullable: true
+        },
+        {
+            name: 'alwaysOn',
+            type: types_.BOOLEAN,
+            optional: true,
+            nullable: true
+        }
+    ]);
+
+    return gestureRecognitionListener.addListener(
+        args.eventCallback,
+        args.errorCallback,
+        args.type,
+        args.alwaysOn
+    );
+};
+
+HumanActivityMonitorManager.prototype.removeGestureRecognitionListener = function() {
+    var args = validator_.validateMethod(arguments, [
+        {
+            name: 'watchId',
+            type: types_.LONG
+        }
+    ]);
+
+    gestureRecognitionListener.removeListener(args.watchId);
+};
+
 function StepDifference(data) {
     SetReadOnlyProperty(this, 'stepCountDifference', data.stepCountDifference);
     SetReadOnlyProperty(this, 'timestamp', data.timestamp);
@@ -734,6 +939,22 @@ function HumanActivityRecorderPressureData(data) {
     SetReadOnlyProperty(this, 'average', data.average);
 }
 
+function GestureData(data) {
+    if (data) {
+        SetReadOnlyProperty(this, 'type', data.type);
+        SetReadOnlyProperty(this, 'event', data.event);
+        SetReadOnlyProperty(this, 'timestamp', data.timestamp);
+
+        if (data.type === 'GESTURE_TILT') {
+            SetReadOnlyProperty(this, 'x', data.x);
+            SetReadOnlyProperty(this, 'y', data.y);
+        } else {
+            SetReadOnlyProperty(this, 'x', null);
+            SetReadOnlyProperty(this, 'y', null);
+        }
+    }
+}
+
 HumanActivityRecorderPressureData.prototype = new HumanActivityRecorderData();
 // prettier-ignore
 HumanActivityRecorderPressureData.prototype.constructor =
index 8deedb4..39fceb7 100644 (file)
@@ -43,7 +43,7 @@ using common::PlatformResult;
 using common::ErrorCode;
 using common::TaskQueue;
 
-HumanActivityMonitorInstance::HumanActivityMonitorInstance() {
+HumanActivityMonitorInstance::HumanActivityMonitorInstance() : gesture_manager_() {
   ScopeLogger();
   using std::placeholders::_1;
   using std::placeholders::_2;
@@ -64,6 +64,11 @@ HumanActivityMonitorInstance::HumanActivityMonitorInstance() {
                 HumanActivityMonitorManagerStopRecorder);
   REGISTER_SYNC("HumanActivityMonitorManager_readRecorderData",
                 HumanActivityMonitorManagerReadRecorderData);
+  REGISTER_SYNC("GestureManager_isGestureSupported", GestureManagerIsGestureSupported);
+  REGISTER_SYNC("GestureManager_addGestureRecognitionListener",
+                GestureManagerAddGestureRecognitionListener);
+  REGISTER_SYNC("GestureManager_removeGestureRecognitionListener",
+                GestureManagerRemoveGestureRecognitionListener);
 #undef REGISTER_SYNC
 }
 
@@ -77,7 +82,7 @@ PlatformResult HumanActivityMonitorInstance::Init() {
     manager_ = std::make_shared<HumanActivityMonitorManager>();
     const PlatformResult& result = manager_->Init();
     if (!result) {
-      LOGGER(ERROR) << "Error initializing manager: " << result.message();
+      LoggerE("Error initializing manager: %s", result.message().c_str());
       manager_.reset();
       return result;
     }
@@ -150,6 +155,12 @@ void HumanActivityMonitorInstance::HumanActivityMonitorManagerStart(const picojs
     CHECK_PRIVILEGE_ACCESS(kPrivilegeLocation, &out);
   }
 
+  if ("WRIST_UP" == type) {
+    LoggerW(
+        "DEPRECATION WARNING: HumanactivityType.WRIST_UP is deprecated since Tizen 4.0. "
+        "Use GestureType and addGestureRecognitionListener to monitor WRIST_UP gesture");
+  }
+
   PlatformResult result = Init();
   if (!result) {
     LogAndReportError(result, &out, ("Failed: Init()"));
@@ -161,7 +172,7 @@ void HumanActivityMonitorInstance::HumanActivityMonitorManagerStart(const picojs
   JsonCallback cb = [this, listener_id](picojson::value* data) -> void {
     ScopeLogger("Entered into asynchronous function, cb");
     if (!data) {
-      LOGGER(ERROR) << "No data passed to json callback";
+      LoggerE("No data passed to json callback");
       return;
     }
 
@@ -192,6 +203,12 @@ void HumanActivityMonitorInstance::HumanActivityMonitorManagerStop(const picojso
     CHECK_PRIVILEGE_ACCESS(kPrivilegeLocation, &out);
   }
 
+  if ("WRIST_UP" == type) {
+    LoggerW(
+        "DEPRECATION WARNING: HumanactivityType.WRIST_UP is deprecated since Tizen 4.0. "
+        "Use GestureType and addGestureRecognitionListener to monitor WRIST_UP gesture");
+  }
+
   PlatformResult result = Init();
   if (!result) {
     LogAndReportError(result, &out, ("Failed: Init()"));
@@ -225,7 +242,7 @@ void HumanActivityMonitorInstance::HumanActivityMonitorManagerAddActivityRecogni
   JsonCallback cb = [this, listener_id](picojson::value* data) -> void {
     ScopeLogger("Entered into asynchronous function, cb");
     if (!data) {
-      LOGGER(ERROR) << "No data passed to json callback";
+      LoggerE("No data passed to json callback");
       return;
     }
 
@@ -381,6 +398,66 @@ void HumanActivityMonitorInstance::HumanActivityMonitorManagerReadRecorderData(
   ReportSuccess(out);
 }
 
+void HumanActivityMonitorInstance::GestureManagerIsGestureSupported(const picojson::value& args,
+                                                                    picojson::object& out) {
+  ScopeLogger();
+
+  CHECK_EXIST(args, "type", out)
+  const auto& type = args.get("type").get<std::string>();
+  bool is_supported = false;
+
+  PlatformResult result = gesture_manager_.IsSupported(type, &is_supported);
+  if (result) {
+    ReportSuccess(picojson::value(is_supported), out);
+  } else {
+    LogAndReportError(result, &out, ("Failed: gesture_manager_->IsSupported()"));
+  }
+}
+
+void HumanActivityMonitorInstance::GestureManagerAddGestureRecognitionListener(
+    const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  CHECK_EXIST(args, "type", out)
+  CHECK_EXIST(args, "alwaysOn", out)
+  const auto& type = args.get("type").get<std::string>();
+  bool always_on = args.get("alwaysOn").get<bool>();
+
+  auto cb = [this](picojson::value* data) -> void {
+    if (!data) {
+      LoggerE("No data passed to json callback");
+      return;
+    }
+
+    Instance::PostMessage(this, data->serialize().c_str());
+  };
+
+  PlatformResult result = gesture_manager_.AddGestureRecognitionListener(type, always_on, cb);
+  if (result) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out, ("Failed: gesture_manager_->AddGestureRecognitionListener()"));
+  }
+}
+
+void HumanActivityMonitorInstance::GestureManagerRemoveGestureRecognitionListener(
+    const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  CHECK_EXIST(args, "type", out)
+  CHECK_EXIST(args, "alwaysOn", out)
+  const auto& type = args.get("type").get<std::string>();
+  bool always_on = args.get("alwaysOn").get<bool>();
+
+  PlatformResult result = gesture_manager_.RemoveGestureRecognitionListener(type, always_on);
+  if (result) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out,
+                      ("Failed: gesture_manager_->RemoveGestureRecognitionListener()"));
+  }
+}
+
 #undef CHECK_EXIST
 
 }  // namespace humanactivitymonitor
index e55dc1f..e0ed215 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "common/extension.h"
 #include "common/platform_result.h"
+#include "humanactivitymonitor/gesture_manager.h"
 #include "humanactivitymonitor/humanactivitymonitor_manager.h"
 
 namespace extension {
@@ -44,8 +45,14 @@ class HumanActivityMonitorInstance : public common::ParsedInstance {
   void HumanActivityMonitorManagerStopRecorder(const picojson::value& args, picojson::object& out);
   void HumanActivityMonitorManagerReadRecorderData(const picojson::value& args,
                                                    picojson::object& out);
+  void GestureManagerIsGestureSupported(const picojson::value& args, picojson::object& out);
+  void GestureManagerAddGestureRecognitionListener(const picojson::value& args,
+                                                   picojson::object& out);
+  void GestureManagerRemoveGestureRecognitionListener(const picojson::value& args,
+                                                      picojson::object& out);
 
   std::shared_ptr<HumanActivityMonitorManager> manager_;
+  GestureManager gesture_manager_;
   common::PlatformResult Init();
 };
 
index 4a4519b..e773809 100644 (file)
@@ -272,11 +272,11 @@ class HumanActivityMonitorManager::Monitor {
   class PedometerMonitor;
 
   explicit Monitor(const std::string& t) : type_(t) {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
   }
 
   virtual ~Monitor() {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
   }
 
   std::string type() const {
@@ -288,7 +288,7 @@ class HumanActivityMonitorManager::Monitor {
   }
 
   PlatformResult SetListener(JsonCallback callback, const picojson::value& args) {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     auto result = IsSupported();
     if (!result) {
@@ -305,7 +305,7 @@ class HumanActivityMonitorManager::Monitor {
   }
 
   PlatformResult UnsetListener() {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     auto result = IsSupported();
     if (!result) {
@@ -322,7 +322,7 @@ class HumanActivityMonitorManager::Monitor {
   }
 
   PlatformResult GetData(picojson::value* data) {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     auto result = IsSupported();
     if (!result) {
@@ -333,7 +333,7 @@ class HumanActivityMonitorManager::Monitor {
   }
 
   PlatformResult StartDataRecorder(int interval, int retention_period) {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     auto result = IsSupported();
     if (!result) {
@@ -344,13 +344,13 @@ class HumanActivityMonitorManager::Monitor {
   }
 
   PlatformResult StopDataRecorder() {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     return StopDataRecorderImpl();
   }
 
   PlatformResult ReadRecorderData(picojson::array* data, const picojson::value& query) {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     auto result = IsSupported();
     if (!result) {
@@ -362,44 +362,44 @@ class HumanActivityMonitorManager::Monitor {
 
  protected:
   virtual PlatformResult IsSupportedImpl(bool* supported) const {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
     *supported = false;
     return PlatformResult(ErrorCode::NO_ERROR);
   }
 
   virtual PlatformResult SetListenerImpl(const picojson::value& args) {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
     return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR, "NOT_SUPPORTED_ERR");
   }
 
   virtual PlatformResult UnsetListenerImpl() {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
     return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR, "NOT_SUPPORTED_ERR");
   }
 
   virtual PlatformResult GetDataImpl(picojson::value* data) const {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
     return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR, "NOT_SUPPORTED_ERR");
   }
 
   virtual PlatformResult StartDataRecorderImpl(int interval, int retention_period) const {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
     return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR, "NOT_SUPPORTED_ERR");
   }
 
   virtual PlatformResult StopDataRecorderImpl() const {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
     return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR, "NOT_SUPPORTED_ERR");
   }
 
   virtual PlatformResult ReadRecorderDataImpl(picojson::array* data, const picojson::value& query) {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
     return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR, "NOT_SUPPORTED_ERR");
   }
 
  public:
   PlatformResult IsSupported() {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     if (!is_supported_) {
       bool is_supported = false;
@@ -428,22 +428,22 @@ class HumanActivityMonitorManager::Monitor::GestureMonitor
     : public HumanActivityMonitorManager::Monitor {
  public:
   explicit GestureMonitor(const std::string& t) : Monitor(t), handle_(nullptr) {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
   }
 
   virtual ~GestureMonitor() override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
     UnsetListenerImpl();
   }
 
  protected:
   virtual PlatformResult IsSupportedImpl(bool* s) const override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     bool supported = false;
 
     int ret = gesture_is_supported(GESTURE_WRIST_UP, &supported);
-    if (ret != SENSOR_ERROR_NONE) {
+    if (GESTURE_ERROR_NONE != ret) {
       if (ret == GESTURE_ERROR_NOT_SUPPORTED) {
         return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR, "WRIST_UP gesture check failed",
                                   ("gesture_is_supported(GESTURE_WRIST_UP), error: %d (%s)", ret,
@@ -460,7 +460,7 @@ class HumanActivityMonitorManager::Monitor::GestureMonitor
   }
 
   virtual PlatformResult SetListenerImpl(const picojson::value&) override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     if (!handle_) {
       int ret = gesture_create(&handle_);
@@ -483,17 +483,17 @@ class HumanActivityMonitorManager::Monitor::GestureMonitor
   }
 
   virtual PlatformResult UnsetListenerImpl() override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     if (handle_) {
       int ret = gesture_stop_recognition(handle_);
       if (GESTURE_ERROR_NONE != ret) {
-        LOGGER(ERROR) << "Failed to stop WRIST_UP detection, error: " << ret;
+        LoggerE("Failed to stop WRIST_UP detection, error: %d", ret);
       }
 
       ret = gesture_release(handle_);
       if (GESTURE_ERROR_NONE != ret) {
-        LOGGER(ERROR) << "Failed to release WRIST_UP handle, error: " << ret;
+        LoggerE("Failed to release WRIST_UP handle, error: %d", ret);
       }
 
       handle_ = nullptr;
@@ -513,7 +513,7 @@ class HumanActivityMonitorManager::Monitor::GestureMonitor
     auto& callback = monitor->event_callback();
 
     if (!callback) {
-      LOGGER(ERROR) << "No WRIST_UP event callback registered, skipping.";
+      LoggerE("No WRIST_UP event callback registered, skipping.");
       return;
     }
 
@@ -539,17 +539,17 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor
         sensor_(s),
         handle_(nullptr),
         recorded_data_(nullptr) {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
   }
 
   virtual ~SensorMonitor() override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
     UnsetListenerImpl();
   }
 
  protected:
   virtual PlatformResult IsSupportedImpl(bool* s) const override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     bool supported = false;
 
@@ -565,7 +565,7 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor
   }
 
   virtual PlatformResult SetListenerImpl(const picojson::value& args) override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     if (!handle_) {
       sensor_h sensor_handle = nullptr;
@@ -618,7 +618,7 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor
   }
 
   virtual PlatformResult UnsetListenerImpl() override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     if (handle_) {
       int ret = sensor_listener_stop(handle_);
@@ -649,7 +649,7 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor
   }
 
   virtual PlatformResult GetDataImpl(picojson::value* data) const override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     if (!handle_) {
       return LogAndCreateResult(ErrorCode::SERVICE_NOT_AVAILABLE_ERR, "SERVICE_NOT_AVAILABLE_ERR");
@@ -680,7 +680,7 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor
   }
 
   virtual PlatformResult StartDataRecorderImpl(int interval, int retention_period) const override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     sensor_recorder_option_h option = nullptr;
 
@@ -711,7 +711,7 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor
   }
 
   virtual PlatformResult StopDataRecorderImpl() const override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     int ret = sensor_recorder_stop(sensor_);
     if (SENSOR_ERROR_NONE != ret) {
@@ -725,7 +725,7 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor
 
   virtual PlatformResult ReadRecorderDataImpl(picojson::array* data,
                                               const picojson::value& query) override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     std::lock_guard<std::mutex> lock(mutex_);
     this->recorded_data_ = data;
@@ -776,7 +776,7 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor
     auto& callback = monitor->event_callback();
 
     if (!callback) {
-      LOGGER(ERROR) << "No sensor event callback registered, skipping.";
+      LoggerE("No sensor event callback registered, skipping.");
       return;
     }
 
@@ -784,7 +784,7 @@ class HumanActivityMonitorManager::Monitor::SensorMonitor
 
     auto result = monitor->converter_(event, &sensor_data.get<picojson::object>());
     if (!result) {
-      LOGGER(ERROR) << "Failed to convert sensor data: " << result.message();
+      LoggerE("Failed to convert sensor data: %s", result.message().c_str());
       return;
     }
 
@@ -994,17 +994,17 @@ class HumanActivityMonitorManager::Monitor::GpsMonitor
     : public HumanActivityMonitorManager::Monitor {
  public:
   explicit GpsMonitor(const std::string& t) : Monitor(t), handle_(nullptr) {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
   }
 
   virtual ~GpsMonitor() override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
     UnsetListenerImpl();
   }
 
  protected:
   virtual PlatformResult IsSupportedImpl(bool* s) const override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     int ret = 0;
     ret = system_info_get_platform_bool("http://tizen.org/feature/location.batch", s);
@@ -1017,7 +1017,7 @@ class HumanActivityMonitorManager::Monitor::GpsMonitor
   }
 
   virtual PlatformResult SetListenerImpl(const picojson::value& args) override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     int ret = 0;
 
@@ -1074,7 +1074,7 @@ class HumanActivityMonitorManager::Monitor::GpsMonitor
   }
 
   virtual PlatformResult UnsetListenerImpl() override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     if (handle_) {
       int ret = location_manager_stop_batch(handle_);
@@ -1106,7 +1106,7 @@ class HumanActivityMonitorManager::Monitor::GpsMonitor
   }
 
   virtual PlatformResult GetDataImpl(picojson::value* data) const override {
-    ScopeLogger(type());
+    ScopeLogger("type %s", type().c_str());
 
     if (!handle_) {
       return LogAndCreateResult(ErrorCode::SERVICE_NOT_AVAILABLE_ERR, "SERVICE_NOT_AVAILABLE_ERR");
@@ -1169,12 +1169,12 @@ class HumanActivityMonitorManager::Monitor::GpsMonitor
     auto& callback = monitor->event_callback();
 
     if (!callback) {
-      LOGGER(ERROR) << "No GPS event callback registered, skipping.";
+      LoggerE("No GPS event callback registered, skipping.");
       return;
     }
 
     if (0 == num_of_location) {
-      LOGGER(ERROR) << "No GPS locations available, skipping.";
+      LoggerE("No GPS locations available, skipping.");
       return;
     }
 
@@ -1182,7 +1182,7 @@ class HumanActivityMonitorManager::Monitor::GpsMonitor
     int ret = location_manager_foreach_location_batch(monitor->handle_, ConvertGpsEvent,
                                                       &gps_info.get<picojson::array>());
     if (LOCATIONS_ERROR_NONE != ret) {
-      LOGGER(ERROR) << "Failed to convert location, error: " << ret;
+      LoggerE("Failed to convert location, error: %d", ret);
       return;
     }
 
@@ -1440,17 +1440,17 @@ HumanActivityMonitorManager::HumanActivityMonitorManager()
   auto convert_hrm = [](sensor_event_s* event, picojson::object* data) -> PlatformResult {
     ScopeLogger("Entered into asynchronous function, convert_hrm");
 
-    LOGGER(DEBUG) << "Sensor event:";
-    LOGGER(DEBUG) << "  |- accuracy: " << event->accuracy;
-    LOGGER(DEBUG) << "  |- timestamp: " << event->timestamp;
-    LOGGER(DEBUG) << "  |- value_count: " << event->value_count;
+    LoggerD("Sensor event:");
+    LoggerD("|- accuracy: %d", event->accuracy);
+    LoggerD("|- timestamp: %llu", event->timestamp);
+    LoggerD("|- value_count: %d", event->value_count);
 
     if (event->value_count < 2) {
       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "To few values of HRM event");
     }
 
-    LOGGER(DEBUG) << "  |- values[0][HR ]: " << event->values[0];
-    LOGGER(DEBUG) << "  |- values[2][RRI]: " << event->values[2];
+    LoggerD("|- values[0][HR ]: %f", event->values[0]);
+    LoggerD("|- values[2][RRI]: %f", event->values[2]);
 
     float hr = floor(event->values[0] + 0.5);  // heart beat rate 0 ~ 220 integer (bpm)
 
index abbe5d8..88e25b0 100644 (file)
@@ -1122,7 +1122,6 @@ common::TizenResult IotconUtils::QueryToJson(iotcon_query_h query, picojson::obj
       auto result = ConvertIotconError(iotcon_query_foreach(
           query,
           [](const char* key, const char* value, void* user_data) -> bool {
-
             ScopeLogger("Entered into asynchronous function, iotcon_query_foreach's argument");
             if (key && value) {
               auto obj = static_cast<picojson::object*>(user_data);
index cc85aad..2676dc1 100644 (file)
@@ -256,7 +256,6 @@ void KeyManagerInstance::SetPermission(const picojson::value& args, picojson::ob
 
   auto set_permissions = [data_name, id,
                           permissions](const std::shared_ptr<picojson::value>& response) -> void {
-
     ScopeLogger("Entered into asynchronous function, set_permissions");
     int ret = ckmc_set_permission(data_name.c_str(), id.c_str(), permissions);
 
index 0331316..7156bcc 100755 (executable)
@@ -23,15 +23,6 @@ var validator_ = utils_.validator;
 var types_ = validator_.Types;
 var native_ = new xwalk.utils.NativeManager(extension);
 
-// TODO(r.galka) CAPI have no dedicated methods for position/shuffle/repeat change.
-// It should be updated when new version of CAPI will be available.
-// For now implementation is using internal commands.
-var internal_commands_ = {
-    sendPlaybackPosition: '__internal_sendPlaybackPosition',
-    sendShuffleMode: '__internal_sendShuffleMode',
-    sendRepeatMode: '__internal_sendRepeatMode'
-};
-
 function ListenerManager(native, listenerName, handle) {
     this.listeners = {};
     this.listenerNameToIds = {};
@@ -724,12 +715,7 @@ MediaControllerServerInfo.prototype.sendPlaybackState = function(
             optional: true,
             nullable: true
         },
-        {
-            name: 'errorCallback',
-            type: types_.FUNCTION,
-            optional: true,
-            nullable: true
-        }
+        { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
     ]);
 
     var data = {
@@ -777,15 +763,11 @@ MediaControllerServerInfo.prototype.sendPlaybackPosition = function(
     };
 
     var data = {
-        position: args.position
+        position: args.position,
+        name: this.name
     };
 
-    sendDefinedCommand(
-        this.name,
-        internal_commands_.sendPlaybackPosition,
-        data,
-        callback
-    );
+    native_.call('MediaControllerServerInfo_sendPlaybackPosition', data, callback);
 };
 
 MediaControllerServerInfo.prototype.sendShuffleMode = function(
@@ -813,9 +795,10 @@ MediaControllerServerInfo.prototype.sendShuffleMode = function(
     };
 
     var data = {
-        mode: args.mode
+        mode: args.mode,
+        name: this.name
     };
-    sendDefinedCommand(this.name, internal_commands_.sendShuffleMode, data, callback);
+    native_.call('MediaControllerServerInfo_sendShuffleMode', data, callback);
 };
 
 MediaControllerServerInfo.prototype.sendRepeatMode = function(
@@ -843,26 +826,12 @@ MediaControllerServerInfo.prototype.sendRepeatMode = function(
     };
 
     var data = {
-        mode: args.mode
+        mode: args.mode,
+        name: this.name
     };
-    sendDefinedCommand(this.name, internal_commands_.sendRepeatMode, data, callback);
+    native_.call('MediaControllerServerInfo_sendRepeatMode', data, callback);
 };
 
-function sendDefinedCommand(name_, command_, data_, callback_) {
-    var nativeData = {
-        command: command_,
-        data: data_,
-        name: name_
-    };
-
-    var replyId = ReplyCommandListener.addListener(callback_);
-
-    nativeData.replyId = replyId;
-    nativeData.listenerId = ReplyCommandListener.listenerName;
-
-    native_.call('MediaControllerServerInfo_sendCommand', nativeData, callback_);
-}
-
 MediaControllerServerInfo.prototype.sendCommand = function(
     command,
     data,
index 7bfb7dd..429f141 100644 (file)
@@ -37,11 +37,19 @@ MediaControllerClient::MediaControllerClient() : handle_(nullptr) {
 
 MediaControllerClient::~MediaControllerClient() {
   ScopeLogger();
-  if (handle_) {
+
+  if (nullptr != server_status_listener_ && !UnsetServerStatusChangeListener()) {
+    LoggerE("Failed to unset server status change listener");
+  }
+
+  if (nullptr != playback_info_listener_ && !UnsetPlaybackInfoListener()) {
+    LoggerE("Failed to unset playback info listener");
+  }
+
+  {
     std::lock_guard<std::mutex> lock(handle_mutex_);
-    int ret = mc_client_destroy(handle_);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      LOGGER(ERROR) << "Unable to destroy media controller client";
+    if (nullptr != handle_ && MEDIA_CONTROLLER_ERROR_NONE != mc_client_destroy(handle_)) {
+      LoggerE("Unable to destroy media controller client");
     }
     handle_ = nullptr;
   }
@@ -50,7 +58,7 @@ MediaControllerClient::~MediaControllerClient() {
 PlatformResult MediaControllerClient::Init() {
   ScopeLogger();
   int ret = mc_client_create(&handle_);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Unable to create media controller client",
         ("mc_client_create() error: %d, message: %s", ret, get_error_message(ret)));
@@ -76,12 +84,12 @@ PlatformResult MediaControllerClient::FindServers(picojson::array* servers) {
   picojson::value latest_server = picojson::value();
   PlatformResult result = GetLatestServerInfo(&latest_server);
   if (!result) {
-    LOGGER(ERROR) << "GetLatestServerInfo failed, error: " << result.message();
+    LoggerE("GetLatestServerInfo failed, error: %s", result.message().c_str());
     return result;
   }
 
   if (latest_server.is<picojson::null>()) {
-    LOGGER(DEBUG) << "No latest server available";
+    LoggerD("No latest server available");
     return PlatformResult(ErrorCode::NO_ERROR);
   }
 
@@ -134,7 +142,7 @@ PlatformResult MediaControllerClient::GetLatestServerInfo(picojson::value* serve
   }
 
   if (!name) {
-    LOGGER(DEBUG) << "No active server available";
+    LoggerD("No active server available");
     return PlatformResult(ErrorCode::NO_ERROR);
   }
 
@@ -142,7 +150,7 @@ PlatformResult MediaControllerClient::GetLatestServerInfo(picojson::value* serve
   PlatformResult result = Types::PlatformEnumToString(Types::kMediaControllerServerState,
                                                       static_cast<int>(state), &state_str);
   if (!result) {
-    LOGGER(ERROR) << "PlatformEnumToString failed, error: " << result.message();
+    LoggerE("PlatformEnumToString failed, error: %s", result.message().c_str());
     return result;
   }
 
@@ -161,7 +169,7 @@ PlatformResult MediaControllerClient::GetPlaybackInfo(const std::string& server_
 
   mc_playback_h playback_h;
   ret = mc_client_get_server_playback_info(handle_, server_name.c_str(), &playback_h);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error getting playback info",
                               ("mc_client_get_server_playback_info() error: %d, message: %s", ret,
                                get_error_message(ret)));
@@ -175,7 +183,7 @@ PlatformResult MediaControllerClient::GetPlaybackInfo(const std::string& server_
   std::string state;
   PlatformResult result = Types::ConvertPlaybackState(playback_h, &state);
   if (!result) {
-    LOGGER(ERROR) << "ConvertPlaybackState failed, error: " << result.message();
+    LoggerE("ConvertPlaybackState failed, error: %s", result.message().c_str());
     return result;
   }
 
@@ -183,14 +191,14 @@ PlatformResult MediaControllerClient::GetPlaybackInfo(const std::string& server_
   double position;
   result = Types::ConvertPlaybackPosition(playback_h, &position);
   if (!result) {
-    LOGGER(ERROR) << "ConvertPlaybackPosition failed, error: " << result.message();
+    LoggerE("ConvertPlaybackPosition failed, error: %s", result.message().c_str());
     return result;
   }
 
   // shuffle mode
   mc_shuffle_mode_e shuffle;
   ret = mc_client_get_server_shuffle_mode(handle_, server_name.c_str(), &shuffle);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error getting shuffle mode",
                               ("mc_client_get_server_shuffle_mode() error: %d, message: %s", ret,
                                get_error_message(ret)));
@@ -199,7 +207,7 @@ PlatformResult MediaControllerClient::GetPlaybackInfo(const std::string& server_
   // repeat mode
   mc_repeat_mode_e repeat;
   ret = mc_client_get_server_repeat_mode(handle_, server_name.c_str(), &repeat);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Error getting repeat mode",
         ("mc_client_get_server_repeat_mode() error: %d, message: %s", ret, get_error_message(ret)));
@@ -229,7 +237,7 @@ PlatformResult MediaControllerClient::GetMetadata(const std::string& server_name
 
   mc_metadata_h metadata_h;
   ret = mc_client_get_server_metadata(handle_, server_name.c_str(), &metadata_h);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Error getting server metadata",
         ("mc_client_get_server_metadata() error: %d, message: %s", ret, get_error_message(ret)));
@@ -247,32 +255,30 @@ PlatformResult MediaControllerClient::GetMetadata(const std::string& server_name
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
-PlatformResult MediaControllerClient::SetServerStatusChangeListener(JsonCallback callback) {
+PlatformResult MediaControllerClient::SetServerStatusChangeListener(const JsonCallback& callback) {
   ScopeLogger();
-  if (callback && server_status_listener_) {
-    return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Listener already registered");
+
+  int ret = mc_client_set_server_update_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)));
   }
 
   server_status_listener_ = callback;
 
-  int ret;
-  if (callback) {  // set platform callbacks
-    ret = mc_client_set_server_update_cb(handle_, OnServerStatusUpdate, this);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      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)));
-    }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
 
-  } else {  // unset platform callbacks
-    ret = mc_client_unset_server_update_cb(handle_);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      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)));
-    }
+PlatformResult MediaControllerClient::UnsetServerStatusChangeListener() {
+  ScopeLogger();
+  int ret = mc_client_unset_server_update_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)));
   }
-
+  server_status_listener_ = nullptr;
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
@@ -281,17 +287,12 @@ void MediaControllerClient::OnServerStatusUpdate(const char* server_name, mc_ser
   ScopeLogger();
   MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
 
-  if (!client->server_status_listener_) {
-    LOGGER(DEBUG) << "No server status listener registered, skipping";
-    return;
-  }
-
   // server state
   std::string state_str;
   PlatformResult result = Types::PlatformEnumToString(Types::kMediaControllerServerState,
                                                       static_cast<int>(state), &state_str);
   if (!result) {
-    LOGGER(ERROR) << "PlatformEnumToString failed, error: " << result.message();
+    LoggerE("PlatformEnumToString failed, error: %s", result.message().c_str());
     return;
   }
 
@@ -304,94 +305,90 @@ void MediaControllerClient::OnServerStatusUpdate(const char* server_name, mc_ser
   client->server_status_listener_(&data);
 }
 
-PlatformResult MediaControllerClient::SetPlaybackInfoListener(JsonCallback callback) {
+PlatformResult MediaControllerClient::SetPlaybackInfoListener(const JsonCallback& callback) {
   ScopeLogger();
-  if (callback && playback_info_listener_) {
-    return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Listener already registered");
-  }
+  int failed_setter = 0;
+  SCOPE_EXIT {
+    // Lambda function used to clean all set listeners (in case of failure of
+    // SetPlaybackInfoListener method).
+    // 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*/};
+
+    // This loop is no-op in case of success.
+    for (int i = 0; i < failed_setter; ++i) {
+      auto ret = unsetters[i](handle_);
+      if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+        LoggerE("Fail (%d) returned by the [%d] unsetter", ret, i);
+      }
+    }
+  };
 
-  playback_info_listener_ = callback;
+  int ret = mc_client_set_playback_update_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)));
+  }
 
-  int ret;
-  if (callback) {  // set platform callbacks
-    ret = mc_client_set_playback_update_cb(handle_, OnPlaybackUpdate, this);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      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)));
-    }
+  ret = mc_client_set_shuffle_mode_update_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)));
+  }
 
-    ret = mc_client_set_shuffle_mode_update_cb(handle_, OnShuffleModeUpdate, this);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      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)));
-    }
+  ret = mc_client_set_repeat_mode_update_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,
+                               get_error_message(ret)));
+  }
 
-    ret = mc_client_set_repeat_mode_update_cb(handle_, OnRepeatModeUpdate, this);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to register repeat mode listener",
-                                ("mc_client_set_repeat_mode_update_cb() error: %d, message: %s",
-                                 ret, get_error_message(ret)));
-    }
+  ret = mc_client_set_metadata_update_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)));
+  }
 
-    ret = mc_client_set_metadata_update_cb(handle_, OnMetadataUpdate, this);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      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)));
-    }
+  playback_info_listener_ = callback;
 
-  } else {  // unset platform callbacks
-    ret = mc_client_unset_playback_update_cb(handle_);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to unregister playback listener",
-                                ("mc_client_unset_playback_update_cb() error: %d, message: %s", ret,
-                                 get_error_message(ret)));
-    }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
 
-    ret = mc_client_unset_shuffle_mode_update_cb(handle_);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
-                                "Unable to unregister shuffle mode listener",
-                                ("mc_client_unset_shuffle_mode_update_cb() error: %d, message: %s",
-                                 ret, get_error_message(ret)));
-    }
+PlatformResult MediaControllerClient::UnsetPlaybackInfoListener() {
+  ScopeLogger();
+  // Even though if one of below functions fails, let's try to unset as much listeners as we can.
+  // In the Javascript layer, the removePlaybackInfoChangeListener() method always succeeds, so we
+  // do not need to catch the returned value.
 
-    ret = mc_client_unset_repeat_mode_update_cb(handle_);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to unregister repeat mode listener",
-                                ("mc_client_unset_repeat_mode_update_cb() error: %d, message: %s",
-                                 ret, get_error_message(ret)));
-    }
+  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_);
 
-    ret = mc_client_unset_metadata_update_cb(handle_);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      LOGGER(ERROR) << "Unable to unregister metadata listener, error: " << ret;
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to unregister metadata listener",
-                                ("mc_client_unset_metadata_update_cb() error: %d, message: %s", ret,
-                                 get_error_message(ret)));
-    }
-  }
+  playback_info_listener_ = nullptr;
 
   return PlatformResult(ErrorCode::NO_ERROR);
-};
+}
 
 void MediaControllerClient::OnPlaybackUpdate(const char* server_name, mc_playback_h playback,
                                              void* user_data) {
   ScopeLogger();
   MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
 
-  if (!client->playback_info_listener_) {
-    LOGGER(DEBUG) << "No playback info listener registered, skipping";
-    return;
-  }
-
   // playback state
   std::string state;
   PlatformResult result = Types::ConvertPlaybackState(playback, &state);
   if (!result) {
-    LOGGER(ERROR) << "ConvertPlaybackState failed, error: " << result.message();
+    LoggerE("ConvertPlaybackState failed, error: %s", result.message().c_str());
     return;
   }
 
@@ -399,7 +396,7 @@ void MediaControllerClient::OnPlaybackUpdate(const char* server_name, mc_playbac
   double position;
   result = Types::ConvertPlaybackPosition(playback, &position);
   if (!result) {
-    LOGGER(ERROR) << "ConvertPlaybackPosition failed, error: " << result.message();
+    LoggerE("ConvertPlaybackPosition failed, error: %s", result.message().c_str());
     return;
   }
 
@@ -419,11 +416,6 @@ void MediaControllerClient::OnShuffleModeUpdate(const char* server_name, mc_shuf
   ScopeLogger();
   MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
 
-  if (!client->playback_info_listener_) {
-    LOGGER(DEBUG) << "No playback info listener registered, skipping";
-    return;
-  }
-
   picojson::value data = picojson::value(picojson::object());
   picojson::object& data_o = data.get<picojson::object>();
 
@@ -439,11 +431,6 @@ void MediaControllerClient::OnRepeatModeUpdate(const char* server_name, mc_repea
   ScopeLogger();
   MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
 
-  if (!client->playback_info_listener_) {
-    LOGGER(DEBUG) << "No playback info listener registered, skipping";
-    return;
-  }
-
   picojson::value data = picojson::value(picojson::object());
   picojson::object& data_o = data.get<picojson::object>();
 
@@ -459,18 +446,13 @@ void MediaControllerClient::OnMetadataUpdate(const char* server_name, mc_metadat
   ScopeLogger();
   MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
 
-  if (!client->playback_info_listener_) {
-    LOGGER(DEBUG) << "No playback info listener registered, skipping";
-    return;
-  }
-
   picojson::value data = picojson::value(picojson::object());
   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>());
   if (!result) {
-    LOGGER(ERROR) << "ConvertMetadata failed, error: " << result.message();
+    LoggerE("ConvertMetadata failed, error: %s", result.message().c_str());
     return;
   }
 
@@ -494,14 +476,14 @@ PlatformResult MediaControllerClient::SendCommand(const std::string& server_name
 
   int ret;
   ret = bundle_add(bundle, "replyId", reply_id.c_str());
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  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 (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Unable to add data to bundle",
         ("bundle_add(data) error: %d, message: %s", ret, get_error_message(ret)));
@@ -509,7 +491,7 @@ PlatformResult MediaControllerClient::SendCommand(const std::string& server_name
 
   ret = mc_client_send_custom_command(handle_, server_name.c_str(), command.c_str(), bundle,
                                       OnCommandReply, this);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  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)));
@@ -537,16 +519,16 @@ void MediaControllerClient::OnCommandReply(const char* server_name, int result_c
   };
 
   ret = bundle_get_str(bundle, "replyId", &reply_id_str);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-    LOGGER(ERROR) << "bundle_get_str(replyId) failed, error: " << ret;
+  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));
 
   ret = bundle_get_str(bundle, "data", &data_str);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-    LOGGER(ERROR) << "bundle_get_str(data) failed, error: " << ret;
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    LoggerE("bundle_get_str(data) failed, error: %d", ret);
     return;
   }
 
@@ -554,7 +536,7 @@ void MediaControllerClient::OnCommandReply(const char* server_name, int result_c
   std::string err;
   picojson::parse(data, data_str, data_str + strlen(data_str), &err);
   if (!err.empty()) {
-    LOGGER(ERROR) << "Failed to parse bundle data: " << err;
+    LoggerE("Failed to parse bundle data: %s", err.c_str());
     return;
   }
   reply_o["data"] = data;
@@ -577,7 +559,7 @@ PlatformResult MediaControllerClient::SendPlaybackState(const std::string& serve
   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));
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  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)));
@@ -588,21 +570,62 @@ PlatformResult MediaControllerClient::SendPlaybackState(const std::string& serve
 
 PlatformResult MediaControllerClient::SendPlaybackPosition(const std::string& server_name,
                                                            double position) {
-  // TODO(r.galka) implement when dedicated method will be available in CAPI
+  ScopeLogger();
+  /* 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_);
+  int ret = mc_client_send_playback_position_cmd(handle_, server_name.c_str(),
+                                                 static_cast<unsigned long long>(position),
+                                                 /*&request_id*/ nullptr);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error sending playback position",
+                              ("mc_client_send_playback_position_cmd() error: %d, message: %s", ret,
+                               get_error_message(ret)));
+  }
 
-  return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR, "Not supported");
+  return PlatformResult(ErrorCode::NO_ERROR);
 }
 
 PlatformResult MediaControllerClient::SendShuffleMode(const std::string& server_name, bool mode) {
-  // TODO(r.galka) implement when dedicated method will be available in CAPI
+  ScopeLogger();
+  /* 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_);
+  int ret = mc_client_send_shuffle_mode_cmd(handle_, server_name.c_str(),
+                                            mode ? MC_SHUFFLE_MODE_ON : MC_SHUFFLE_MODE_OFF,
+                                            /*&request_id*/ nullptr);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "Error sending shuffle mode",
+        ("mc_client_send_shuffle_mode_cmd() error: %d, message: %s", ret, get_error_message(ret)));
+  }
 
-  return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR, "Not supported");
+  return PlatformResult(ErrorCode::NO_ERROR);
 }
 
 PlatformResult MediaControllerClient::SendRepeatMode(const std::string& server_name, bool mode) {
-  // TODO(r.galka) implement when dedicated method will be available in CAPI
+  ScopeLogger();
+  /* TODO: Prepare an ACR and propose use case for request_id.
+  char* request_id = nullptr;
+  SCOPE_EXIT {
+    free(request_id);
+  };*/
+  int ret = mc_client_send_repeat_mode_cmd(handle_, server_name.c_str(),
+                                           mode ? MC_REPEAT_MODE_ON : MC_REPEAT_MODE_OFF,
+                                           /*&request_id*/ nullptr);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "Error sending repeat mode",
+        ("mc_client_send_repeat_mode_cmd() error: %d, message: %s", ret, get_error_message(ret)));
+  }
 
-  return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR, "Not supported");
+  return PlatformResult(ErrorCode::NO_ERROR);
 }
 
 }  // namespace mediacontroller
index 2ebbc16..f1aa8c4 100644 (file)
@@ -50,8 +50,11 @@ class MediaControllerClient {
                                      const picojson::value& data, const std::string& reply_id,
                                      const JsonCallback& reply_cb);
 
-  common::PlatformResult SetServerStatusChangeListener(JsonCallback callback);
-  common::PlatformResult SetPlaybackInfoListener(JsonCallback callback);
+  common::PlatformResult SetServerStatusChangeListener(const JsonCallback& callback);
+  common::PlatformResult UnsetServerStatusChangeListener();
+
+  common::PlatformResult SetPlaybackInfoListener(const JsonCallback& callback);
+  common::PlatformResult UnsetPlaybackInfoListener();
 
  private:
   mc_client_h handle_;
index 6f2a961..350c4d6 100644 (file)
@@ -250,7 +250,7 @@ void MediaControllerInstance::MediaControllerServerAddChangeRequestPlaybackInfoL
 
   JsonCallback callback = [this, args](picojson::value* data) -> void {
     if (!data) {
-      LOGGER(ERROR) << "No data passed to json callback";
+      LoggerE("No data passed to json callback");
       return;
     }
 
@@ -260,7 +260,10 @@ void MediaControllerInstance::MediaControllerServerAddChangeRequestPlaybackInfoL
     Instance::PostMessage(this, data->serialize().c_str());
   };
 
-  server_->SetChangeRequestPlaybackInfoListener(callback);
+  auto result = server_->SetChangeRequestPlaybackInfoListener(callback);
+  if (!result) {
+    LogAndReportError(result, &out);
+  }
 
   ReportSuccess(out);
 }
@@ -274,7 +277,10 @@ void MediaControllerInstance::MediaControllerServerRemoveChangeRequestPlaybackIn
     return;
   }
 
-  server_->SetChangeRequestPlaybackInfoListener(nullptr);
+  auto result = server_->UnsetChangeRequestPlaybackInfoListener();
+  if (!result) {
+    LogAndReportError(result, &out);
+  }
 }
 
 void MediaControllerInstance::MediaControllerServerAddCommandListener(const picojson::value& args,
@@ -293,7 +299,10 @@ void MediaControllerInstance::MediaControllerServerAddCommandListener(const pico
     Instance::PostMessage(this, request->serialize().c_str());
   };
 
-  server_->set_command_listener(on_command);
+  auto result = server_->SetCommandListener(on_command);
+  if (!result) {
+    LogAndReportError(result, &out);
+  }
 
   ReportSuccess(out);
 }
@@ -326,7 +335,10 @@ void MediaControllerInstance::MediaControllerServerRemoveCommandListener(
     return;
   }
 
-  server_->set_command_listener(nullptr);
+  auto result = server_->UnsetCommandListener();
+  if (!result) {
+    LogAndReportError(result, &out);
+  }
 
   ReportSuccess(out);
 }
@@ -615,7 +627,7 @@ void MediaControllerInstance::MediaControllerServerInfoAddServerStatusChangeList
 
   JsonCallback callback = [this, args](picojson::value* data) -> void {
     if (nullptr == data) {
-      LOGGER(ERROR) << "No data passed to json callback";
+      LoggerE("No data passed to json callback");
       return;
     }
 
@@ -625,7 +637,10 @@ void MediaControllerInstance::MediaControllerServerInfoAddServerStatusChangeList
     Instance::PostMessage(this, data->serialize().c_str());
   };
 
-  client_->SetServerStatusChangeListener(callback);
+  auto result = client_->SetServerStatusChangeListener(callback);
+  if (!result) {
+    LogAndReportError(result, &out);
+  }
 
   ReportSuccess(out);
 }
@@ -639,7 +654,10 @@ void MediaControllerInstance::MediaControllerServerInfoRemoveServerStatusChangeL
     return;
   }
 
-  client_->SetServerStatusChangeListener(nullptr);
+  auto result = client_->UnsetServerStatusChangeListener();
+  if (!result) {
+    LogAndReportError(result, &out);
+  }
 }
 
 void MediaControllerInstance::MediaControllerServerInfoAddPlaybackInfoChangeListener(
@@ -655,7 +673,7 @@ void MediaControllerInstance::MediaControllerServerInfoAddPlaybackInfoChangeList
 
   JsonCallback callback = [this, args](picojson::value* data) -> void {
     if (!data) {
-      LOGGER(ERROR) << "No data passed to json callback";
+      LoggerE("No data passed to json callback");
       return;
     }
 
@@ -665,7 +683,10 @@ void MediaControllerInstance::MediaControllerServerInfoAddPlaybackInfoChangeList
     Instance::PostMessage(this, data->serialize().c_str());
   };
 
-  client_->SetPlaybackInfoListener(callback);
+  auto result = client_->SetPlaybackInfoListener(callback);
+  if (!result) {
+    LogAndReportError(result, &out);
+  }
 
   ReportSuccess(out);
 }
@@ -678,7 +699,10 @@ void MediaControllerInstance::MediaControllerServerInfoRemovePlaybackInfoChangeL
     return;
   }
 
-  client_->SetPlaybackInfoListener(nullptr);
+  auto result = client_->UnsetPlaybackInfoListener();
+  if (!result) {
+    LogAndReportError(result, &out);
+  }
 }
 
 #undef CHECK_EXIST
index d280d8a..86204fb 100644 (file)
 namespace extension {
 namespace mediacontroller {
 
-namespace {
-// The privileges that are required in Application API
-const std::string kInternalCommandSendPlaybackPosition = "__internal_sendPlaybackPosition";
-const std::string kInternalCommandSendShuffleMode = "__internal_sendShuffleMode";
-const std::string kInternalCommandSendRepeatMode = "__internal_sendRepeatMode";
-}  // namespace
-
 using common::PlatformResult;
 using common::ErrorCode;
 
-MediaControllerServer::MediaControllerServer() : handle_(nullptr) {
+MediaControllerServer::MediaControllerServer()
+    : handle_(nullptr),
+      playback_state_(MC_PLAYBACK_STATE_STOPPED),
+      position_(0ULL),
+      shuffle_mode_(MC_SHUFFLE_MODE_OFF),
+      repeat_mode_(MC_REPEAT_MODE_OFF),
+      is_shuffle_mode_set_(false),
+      is_repeat_mode_set_(false) {
   ScopeLogger();
 }
 
 MediaControllerServer::~MediaControllerServer() {
   ScopeLogger();
 
-  if (handle_) {
-    int ret;
-    ret = mc_server_unset_custom_command_received_cb(handle_);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      LOGGER(ERROR) << "Unable to unset command callback, error: " << ret;
-    }
+  if (nullptr != change_request_playback_info_listener_ &&
+      !UnsetChangeRequestPlaybackInfoListener()) {
+    LoggerE("Failed to unset change request playback info listener");
+  }
 
-    ret = mc_server_destroy(handle_);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      LOGGER(ERROR) << "mc_server_destroy() failed, error: " << ret;
-    }
+  if (nullptr != command_listener_ && !UnsetCommandListener()) {
+    LoggerE("Failed to unset command listener");
+  }
+
+  if (nullptr != handle_ && MEDIA_CONTROLLER_ERROR_NONE != mc_server_destroy(handle_)) {
+    LoggerE("Unable to destroy media controller server");
   }
   handle_ = nullptr;
 }
@@ -63,19 +63,12 @@ PlatformResult MediaControllerServer::Init() {
   ScopeLogger();
 
   int ret = mc_server_create(&handle_);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Unable to create media controller server",
         ("mc_server_create() error: %d, message: %s", ret, get_error_message(ret)));
   }
 
-  ret = mc_server_set_custom_command_received_cb(handle_, OnCommandReceived, this);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-    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)));
-  }
-
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
@@ -90,15 +83,22 @@ PlatformResult MediaControllerServer::SetPlaybackState(const std::string& state)
     return result;
   }
 
+  if (static_cast<mc_playback_states_e>(state_int) == 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));
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  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);
+
   ret = mc_server_update_playback_info(handle_);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Error updating playback info",
         ("mc_server_update_playback_info() error: %d, message: %s", ret, get_error_message(ret)));
@@ -110,15 +110,22 @@ PlatformResult MediaControllerServer::SetPlaybackState(const std::string& state)
 PlatformResult MediaControllerServer::SetPlaybackPosition(double position) {
   ScopeLogger();
 
+  if (static_cast<unsigned long long>(position) == position_) {
+    LoggerD("No change in playback position requested, skipping");
+    return PlatformResult(ErrorCode::NO_ERROR);
+  }
+
   int ret = mc_server_set_playback_position(handle_, static_cast<unsigned long long>(position));
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Error setting playback position",
         ("mc_server_set_playback_position() error: %d, message: %s", ret, get_error_message(ret)));
   }
 
+  position_ = static_cast<unsigned long long>(position);
+
   ret = mc_server_update_playback_info(handle_);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Error updating playback info",
         ("mc_server_update_playback_info() error: %d, message: %s", ret, get_error_message(ret)));
@@ -130,26 +137,44 @@ PlatformResult MediaControllerServer::SetPlaybackPosition(double position) {
 PlatformResult MediaControllerServer::SetShuffleMode(bool mode) {
   ScopeLogger();
 
-  int ret = mc_server_update_shuffle_mode(handle_, mode ? MC_SHUFFLE_MODE_ON : MC_SHUFFLE_MODE_OFF);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  mc_shuffle_mode_e shuffle_mode = mode ? MC_SHUFFLE_MODE_ON : MC_SHUFFLE_MODE_OFF;
+  if ((shuffle_mode == shuffle_mode_) && (is_shuffle_mode_set_)) {
+    LoggerD("No change in shuffle mode requested, skipping");
+    return PlatformResult(ErrorCode::NO_ERROR);
+  }
+
+  int ret = mc_server_update_shuffle_mode(handle_, shuffle_mode);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Error updating shuffle mode",
         ("mc_server_update_shuffle_mode() error: %d, message: %s", ret, get_error_message(ret)));
   }
 
+  shuffle_mode_ = shuffle_mode;
+  is_shuffle_mode_set_ = true;
+
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
 PlatformResult MediaControllerServer::SetRepeatMode(bool mode) {
   ScopeLogger();
 
-  int ret = mc_server_update_repeat_mode(handle_, mode ? MC_REPEAT_MODE_ON : MC_REPEAT_MODE_OFF);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  mc_repeat_mode_e repeat_mode = mode ? MC_REPEAT_MODE_ON : MC_REPEAT_MODE_OFF;
+  if ((repeat_mode == repeat_mode_) && (is_repeat_mode_set_)) {
+    LoggerD("No change in repeat mode requested, skipping");
+    return PlatformResult(ErrorCode::NO_ERROR);
+  }
+
+  int ret = mc_server_update_repeat_mode(handle_, repeat_mode);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Error updating repeat mode",
         ("mc_server_update_repeat_mode() error: %d, message: %s", ret, get_error_message(ret)));
   }
 
+  repeat_mode_ = repeat_mode;
+  is_repeat_mode_set_ = true;
+
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
@@ -166,7 +191,7 @@ PlatformResult MediaControllerServer::SetMetadata(const picojson::object& metada
 
     ret = mc_server_set_metadata(handle_, static_cast<mc_meta_e>(attribute_int),
                                  i->second.to_str().c_str());
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+    if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error setting metadata",
                                 ("mc_server_set_metadata(%s) error: %d, message: %s",
                                  i->first.c_str(), ret, get_error_message(ret)));
@@ -174,7 +199,7 @@ PlatformResult MediaControllerServer::SetMetadata(const picojson::object& metada
   }
 
   ret = mc_server_update_metadata(handle_);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Error updating metadata",
         ("mc_server_update_metadata() error: %d, message: %s", ret, get_error_message(ret)));
@@ -198,14 +223,14 @@ void MediaControllerServer::OnCommandReceived(const char* client_name, const cha
   };
 
   ret = bundle_get_str(bundle, "data", &data_str);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-    LOGGER(ERROR) << "bundle_get_str(data) failed, error: " << ret;
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    LoggerE("bundle_get_str(data) failed, error: %d", ret);
     return;
   }
 
   ret = bundle_get_str(bundle, "replyId", &reply_id_str);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-    LOGGER(ERROR) << "bundle_get_str(replyId) failed, error: " << ret;
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    LoggerE("bundle_get_str(replyId) failed, error: %d", ret);
     return;
   }
 
@@ -213,48 +238,19 @@ void MediaControllerServer::OnCommandReceived(const char* client_name, const cha
   std::string err;
   picojson::parse(data, data_str, data_str + strlen(data_str), &err);
   if (!err.empty()) {
-    LOGGER(ERROR) << "Failed to parse bundle data: " << err;
-    return;
-  }
-
-  // TODO(r.galka) CAPI have no dedicated methods for position/shuffle/repeat change.
-  // It should be updated when new version of CAPI will be available.
-  // For now implementation is using internal commands.
-  if (command == kInternalCommandSendPlaybackPosition) {
-    double position = data.get("position").get<double>();
-    server->SetPlaybackPosition(position);
-    server->OnPlaybackPositionCommand(client_name, static_cast<unsigned long long>(position),
-                                      server);
-    server->CommandReply(client_name, reply_id_str, data);
-    return;
-  }
-  if (command == kInternalCommandSendShuffleMode) {
-    bool mode = data.get("mode").get<bool>();
-    server->SetShuffleMode(mode);
-    server->OnShuffleModeCommand(client_name, mode ? MC_SHUFFLE_MODE_ON : MC_SHUFFLE_MODE_OFF,
-                                 server);
-    server->CommandReply(client_name, reply_id_str, data);
-    return;
-  }
-  if (command == kInternalCommandSendRepeatMode) {
-    bool mode = data.get("mode").get<bool>();
-    server->SetRepeatMode(mode);
-    server->OnRepeatModeCommand(client_name, mode ? MC_REPEAT_MODE_ON : MC_REPEAT_MODE_OFF, server);
-    server->CommandReply(client_name, reply_id_str, data);
+    LoggerE("Failed to parse bundle data: %s", err.c_str());
     return;
   }
 
-  if (server->command_listener_) {
-    picojson::value request = picojson::value(picojson::object());
-    picojson::object& request_o = request.get<picojson::object>();
+  picojson::value request = picojson::value(picojson::object());
+  picojson::object& request_o = request.get<picojson::object>();
 
-    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["data"] = data;
+  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["data"] = data;
 
-    server->command_listener_(&request);
-  }
+  server->command_listener_(&request);
 }
 
 PlatformResult MediaControllerServer::CommandReply(const std::string& client_name,
@@ -270,21 +266,21 @@ PlatformResult MediaControllerServer::CommandReply(const std::string& client_nam
   };
 
   ret = bundle_add(bundle, "replyId", reply_id.c_str());
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  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 (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Unable to add data to bundle",
         ("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);
-  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+  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)));
@@ -293,34 +289,134 @@ PlatformResult MediaControllerServer::CommandReply(const std::string& client_nam
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
-PlatformResult MediaControllerServer::SetChangeRequestPlaybackInfoListener(JsonCallback callback) {
+PlatformResult MediaControllerServer::SetCommandListener(const JsonCallback& callback) {
   ScopeLogger();
 
-  if (callback && change_request_playback_info_listener_) {
-    return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Listener already registered");
+  int ret = mc_server_set_custom_command_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)));
   }
+  command_listener_ = callback;
 
-  change_request_playback_info_listener_ = callback;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
 
-  int ret;
-  if (callback) {  // set platform callbacks
-    ret = mc_server_set_playback_state_command_received_cb(handle_, OnPlaybackStateCommand, this);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      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,
-           get_error_message(ret)));
-    }
-  } else {  // unset platform callbacks
-    ret = mc_server_unset_playback_state_command_received_cb(handle_);
-    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      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,
-           get_error_message(ret)));
+PlatformResult MediaControllerServer::UnsetCommandListener() {
+  ScopeLogger();
+
+  int ret = mc_server_unset_custom_command_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",
+                               ret, get_error_message(ret)));
+  }
+  command_listener_ = nullptr;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult MediaControllerServer::SetChangeRequestPlaybackInfoListener(
+    const JsonCallback& callback) {
+  ScopeLogger();
+  int failed_setter = 0;
+  SCOPE_EXIT {
+    // Lambda function used to clean all set listeners (in case of failure of
+    // SetPlaybackInfoListener method).
+    // 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_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*/};
+
+    // This loop is no-op in case of success.
+    for (int i = 0; i < failed_setter; ++i) {
+      auto ret = unsetters[i](handle_);
+      if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+        LoggerE("Fail (%d) returned by the [%d] unsetter", ret, i);
+      }
     }
+  };
+
+  int ret = mc_server_set_playback_state_command_received_cb(handle_, OnPlaybackStateCommand, 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,
+         get_error_message(ret)));
+  }
+
+  ret = mc_server_set_playback_position_cmd_received_cb(handle_, OnPlaybackPositionCommand, this);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    failed_setter = 1;
+    return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "Unable to set playback position command listener",
+        ("mc_server_set_playback_position_cmd_received_cb() error: %d, message: %s", ret,
+         get_error_message(ret)));
+  }
+
+  ret = mc_server_set_shuffle_mode_cmd_received_cb(handle_, OnShuffleModeCommand, this);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    failed_setter = 2;
+    return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "Unable to set shuffle mode command listener",
+        ("mc_server_set_shuffle_mode_cmd_received_cb() error: %d, message: %s", ret,
+         get_error_message(ret)));
+  }
+
+  ret = mc_server_set_repeat_mode_cmd_received_cb(handle_, OnRepeatModeCommand, this);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    failed_setter = 3;
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to set repeat mode command listener",
+                              ("mc_server_set_repeat_mode_cmd_received_cb() error: %d, message: %s",
+                               ret, get_error_message(ret)));
   }
 
+  change_request_playback_info_listener_ = callback;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult MediaControllerServer::UnsetChangeRequestPlaybackInfoListener() {
+  ScopeLogger();
+
+  int ret = mc_server_unset_playback_state_command_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,
+         get_error_message(ret)));
+  }
+
+  ret = mc_server_unset_playback_position_cmd_received_cb(handle_);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "Unable to unset playback position command listener",
+        ("mc_server_unset_playback_position_cmd_received_cb() error: %d, message: %s", ret,
+         get_error_message(ret)));
+  }
+
+  ret = mc_server_unset_shuffle_mode_cmd_received_cb(handle_);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "Unable to unset shuffle mode command listener",
+        ("mc_server_unset_shuffle_mode_cmd_received_cb() error: %d, message: %s", ret,
+         get_error_message(ret)));
+  }
+
+  ret = mc_server_unset_repeat_mode_cmd_received_cb(handle_);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "Unable to unset repeat mode command listener",
+        ("mc_server_unset_repeat_mode_cmd_received_cb() error: %d, message: %s", ret,
+         get_error_message(ret)));
+  }
+
+  change_request_playback_info_listener_ = nullptr;
+
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
@@ -330,8 +426,8 @@ void MediaControllerServer::OnPlaybackStateCommand(const char* client_name,
 
   MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
 
-  if (!server->change_request_playback_info_listener_) {
-    LOGGER(DEBUG) << "No change request playback info listener registered, skipping";
+  if (server->playback_state_ == state_e) {
+    LoggerD("The media playback state did not change, skipping");
     return;
   }
 
@@ -339,7 +435,7 @@ void MediaControllerServer::OnPlaybackStateCommand(const char* client_name,
   PlatformResult result = Types::PlatformEnumToString(Types::kMediaControllerPlaybackState,
                                                       static_cast<int>(state_e), &state);
   if (!result) {
-    LOGGER(ERROR) << "PlatformEnumToString failed, error: " << result.message();
+    LoggerE("PlatformEnumToString failed, error: %s", result.message().c_str());
     return;
   }
 
@@ -353,14 +449,15 @@ void MediaControllerServer::OnPlaybackStateCommand(const char* client_name,
 }
 
 void MediaControllerServer::OnPlaybackPositionCommand(const char* client_name,
+                                                      const char* request_id,
                                                       unsigned long long position,
                                                       void* user_data) {
   ScopeLogger();
 
   MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
 
-  if (!server->change_request_playback_info_listener_) {
-    LOGGER(DEBUG) << "No change request playback info listener registered, skipping";
+  if (server->position_ == position) {
+    LoggerD("The position did not change, skipping");
     return;
   }
 
@@ -373,14 +470,14 @@ void MediaControllerServer::OnPlaybackPositionCommand(const char* client_name,
   server->change_request_playback_info_listener_(&data);
 }
 
-void MediaControllerServer::OnShuffleModeCommand(const char* client_name, mc_shuffle_mode_e mode,
-                                                 void* user_data) {
+void MediaControllerServer::OnShuffleModeCommand(const char* client_name, const char* request_id,
+                                                 mc_shuffle_mode_e mode, void* user_data) {
   ScopeLogger();
 
   MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
 
-  if (!server->change_request_playback_info_listener_) {
-    LOGGER(DEBUG) << "No change request playback info listener registered, skipping";
+  if (server->shuffle_mode_ == mode) {
+    LoggerD("The shuffle mode did not change, skipping");
     return;
   }
 
@@ -393,14 +490,14 @@ void MediaControllerServer::OnShuffleModeCommand(const char* client_name, mc_shu
   server->change_request_playback_info_listener_(&data);
 }
 
-void MediaControllerServer::OnRepeatModeCommand(const char* client_name, mc_repeat_mode_e mode,
-                                                void* user_data) {
+void MediaControllerServer::OnRepeatModeCommand(const char* client_name, const char* request_id,
+                                                mc_repeat_mode_e mode, void* user_data) {
   ScopeLogger();
 
   MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
 
-  if (!server->change_request_playback_info_listener_) {
-    LOGGER(DEBUG) << "No change request playback info listener registered, skipping";
+  if (server->repeat_mode_ == mode) {
+    LoggerD("The repeat mode did not change, skipping");
     return;
   }
 
index 8654a69..2fc1803 100644 (file)
@@ -38,28 +38,36 @@ class MediaControllerServer {
   common::PlatformResult SetRepeatMode(bool mode);
   common::PlatformResult SetMetadata(const picojson::object& metadata);
 
-  common::PlatformResult SetChangeRequestPlaybackInfoListener(JsonCallback callback);
+  common::PlatformResult SetChangeRequestPlaybackInfoListener(const JsonCallback& callback);
+  common::PlatformResult UnsetChangeRequestPlaybackInfoListener();
 
   common::PlatformResult CommandReply(const std::string& client_name, const std::string& reply_id,
                                       const picojson::value& data);
 
-  void set_command_listener(const JsonCallback& func) {
-    command_listener_ = func;
-  }
+  common::PlatformResult SetCommandListener(const JsonCallback& callback);
+  common::PlatformResult UnsetCommandListener();
 
  private:
   mc_server_h handle_;
 
   JsonCallback change_request_playback_info_listener_;
+  mc_playback_states_e playback_state_;
+  unsigned long long position_;
+  mc_shuffle_mode_e shuffle_mode_;
+  mc_repeat_mode_e repeat_mode_;
+  bool is_shuffle_mode_set_;
+  bool is_repeat_mode_set_;
+
   JsonCallback command_listener_;
 
   static void OnPlaybackStateCommand(const char* client_name, mc_playback_states_e state_e,
                                      void* user_data);
-  static void OnPlaybackPositionCommand(const char* client_name, unsigned long long position,
-                                        void* user_data);
-  static void OnShuffleModeCommand(const char* client_name, mc_shuffle_mode_e mode,
-                                   void* user_data);
-  static void OnRepeatModeCommand(const char* client_name, mc_repeat_mode_e mode, 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,
+                                   mc_shuffle_mode_e mode, void* user_data);
+  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);
index a08aeff..f56c431 100644 (file)
@@ -143,7 +143,7 @@ PlatformResult Types::ConvertPlaybackState(mc_playback_h playback_h, std::string
   PlatformResult result = Types::PlatformEnumToString(Types::kMediaControllerPlaybackState,
                                                       static_cast<int>(state_e), state);
   if (!result) {
-    LOGGER(ERROR) << "PlatformEnumToString failed, error: " << result.message();
+    LoggerE("PlatformEnumToString failed, error: %s", result.message().c_str());
     return result;
   }
 
@@ -175,7 +175,7 @@ PlatformResult Types::ConvertMetadata(mc_metadata_h metadata_h, picojson::object
   PlatformResult result =
       GetPlatformEnumMap(Types::kMediaControllerMetadataAttribute, &metadata_fields);
   if (!result) {
-    LOGGER(ERROR) << "GetPlatformEnumMap failed, error: " << result.message();
+    LoggerE("GetPlatformEnumMap failed, error: %s", result.message().c_str());
     return result;
   }
 
index 5ec6c58..b3205dc 100644 (file)
@@ -97,7 +97,7 @@ void MessageProxy::signalCallback(GDBusConnection* connection, const gchar* send
       LoggerD("Unrecognized status: %d", status);
   }
   if (ret.IsError()) {
-    LoggerE("%d (%s)", ret.error_code(), (ret.message()).c_str());
+    LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
   }
   g_free(name);
 }
index 1037576..ebc9128 100644 (file)
@@ -45,34 +45,6 @@ bool AbstractFilter::isMatching(const FilterableObject* const tested_object) con
   return false;
 }
 
-AttributeFilterPtr castToAttributeFilter(AbstractFilterPtr from) {
-  if (ATTRIBUTE_FILTER != from->getFilterType()) {
-    LoggerE("Trying to get AttributeFilterPtr but filter's type is: %d", from->getFilterType());
-    return AttributeFilterPtr();
-  }
-
-  return std::dynamic_pointer_cast<AttributeFilter>(from);
-}
-
-AttributeRangeFilterPtr castToAttributeRangeFilter(AbstractFilterPtr from) {
-  if (ATTRIBUTE_RANGE_FILTER != from->getFilterType()) {
-    LoggerE("Trying to get AttributeRangeFilterPtr but filter's type is: %d",
-            from->getFilterType());
-    return AttributeRangeFilterPtr();
-  }
-
-  return std::dynamic_pointer_cast<AttributeRangeFilter>(from);
-}
-
-CompositeFilterPtr castToCompositeFilter(AbstractFilterPtr from) {
-  if (COMPOSITE_FILTER != from->getFilterType()) {
-    LoggerE("Trying to get CompositeFilterPtr but filter's type is: %d", from->getFilterType());
-    return CompositeFilterPtr();
-  }
-
-  return std::dynamic_pointer_cast<CompositeFilter>(from);
-}
-
 namespace {
 
 inline std::string convertToLowerCase(const std::string& input_string) {
@@ -170,8 +142,9 @@ bool FilterUtils::isTimeStampInRange(const time_t& time_stamp, tizen::AnyPtr& in
 
   bool is_in_range = FilterUtils::isBetweenTimeRange(time_stamp, from_time, to_time);
 
-  LoggerD("%d is%s in time range <%d, %d>", time_stamp, (is_in_range ? "" : " NOT"), from_time,
-          to_time);
+  LoggerD("%lld is%s in time range <%lld, %lld>", static_cast<long long>(time_stamp),
+          (is_in_range ? "" : " NOT"), static_cast<long long>(from_time),
+          static_cast<long long>(to_time));
 
   return is_in_range;
 }
index 3d91173..db721e9 100644 (file)
 namespace extension {
 namespace tizen {
 
-class AttributeFilter;
-typedef std::shared_ptr<AttributeFilter> AttributeFilterPtr;
-
-class AttributeRangeFilter;
-typedef std::shared_ptr<AttributeRangeFilter> AttributeRangeFilterPtr;
-
-class CompositeFilter;
-typedef std::shared_ptr<CompositeFilter> CompositeFilterPtr;
-
 class AbstractFilter;
 typedef std::shared_ptr<AbstractFilter> AbstractFilterPtr;
 typedef std::vector<AbstractFilterPtr> AbstractFilterPtrVector;
@@ -77,13 +68,6 @@ class AbstractFilter {
   FilterType m_filter_type;
 };
 
-/**
- * Returns NULL shared_ptr if cast is not possible (incorrect type)
- */
-AttributeFilterPtr castToAttributeFilter(AbstractFilterPtr from);
-AttributeRangeFilterPtr castToAttributeRangeFilter(AbstractFilterPtr from);
-CompositeFilterPtr castToCompositeFilter(AbstractFilterPtr from);
-
 // class JSFilterArray : public Common::JSArray<AbstractFilterPtr> {
 // public:
 //    JSFilterArray(JSContextRef ctx, JSObjectRef array):
@@ -127,8 +111,4 @@ class FilterUtils {
 }  // Tizen
 }  // DeviceAPI
 
-#include "AttributeFilter.h"
-#include "AttributeRangeFilter.h"
-#include "CompositeFilter.h"
-
 #endif  // __TIZEN_TIZEN_ABSTRACT_FILTER_H__
index 352c0a8..58014d4 100644 (file)
@@ -64,5 +64,14 @@ bool AttributeFilter::isMatching(const FilterableObject *const filtered_object)
   return filtered_object->isMatchingAttribute(m_attribute_name, m_match_flag, m_match_value);
 }
 
+AttributeFilterPtr castToAttributeFilter(AbstractFilterPtr from) {
+  if (ATTRIBUTE_FILTER != from->getFilterType()) {
+    LoggerE("Trying to get AttributeFilterPtr but filter's type is: %d", from->getFilterType());
+    return AttributeFilterPtr();
+  }
+
+  return std::dynamic_pointer_cast<AttributeFilter>(from);
+}
+
 }  // Tizen
 }  // DeviceAPI
index 0f72188..bd9ceab 100644 (file)
@@ -47,6 +47,11 @@ class AttributeFilter : public AbstractFilter {
   AnyPtr m_match_value;
 };
 
+/**
+ * Returns NULL shared_ptr if cast is not possible (incorrect type)
+ */
+AttributeFilterPtr castToAttributeFilter(AbstractFilterPtr from);
+
 }  // Tizen
 }  // DeviceAPI
 
index d343767..4c06346 100644 (file)
@@ -64,5 +64,15 @@ bool AttributeRangeFilter::isMatching(const FilterableObject *const filtered_obj
   return filtered_object->isMatchingAttributeRange(m_attribute_name, m_initial_value, m_end_value);
 }
 
+AttributeRangeFilterPtr castToAttributeRangeFilter(AbstractFilterPtr from) {
+  if (ATTRIBUTE_RANGE_FILTER != from->getFilterType()) {
+    LoggerE("Trying to get AttributeRangeFilterPtr but filter's type is: %d",
+            from->getFilterType());
+    return AttributeRangeFilterPtr();
+  }
+
+  return std::dynamic_pointer_cast<AttributeRangeFilter>(from);
+}
+
 }  // Tizen
 }  // DeviceAPI
index d847c4c..267faa2 100644 (file)
@@ -49,6 +49,11 @@ class AttributeRangeFilter : public AbstractFilter {
   AnyPtr m_end_value;
 };
 
+/**
+ * Returns NULL shared_ptr if cast is not possible (incorrect type)
+ */
+AttributeRangeFilterPtr castToAttributeRangeFilter(AbstractFilterPtr from);
+
 }  // Tizen
 }  // DeviceAPI
 
index d9b4ff7..275c61c 100644 (file)
@@ -87,5 +87,14 @@ bool CompositeFilter::isMatching(const FilterableObject* const filtered_object)
   return composite_result;
 }
 
+CompositeFilterPtr castToCompositeFilter(AbstractFilterPtr from) {
+  if (COMPOSITE_FILTER != from->getFilterType()) {
+    LoggerE("Trying to get CompositeFilterPtr but filter's type is: %d", from->getFilterType());
+    return CompositeFilterPtr();
+  }
+
+  return std::dynamic_pointer_cast<CompositeFilter>(from);
+}
+
 }  // Tizen
 }  // DeviceAPI
index 3b05b84..696e75d 100644 (file)
@@ -44,6 +44,11 @@ class CompositeFilter : public AbstractFilter {
   AbstractFilterPtrVector m_filters;
 };
 
+/**
+ * Returns NULL shared_ptr if cast is not possible (incorrect type)
+ */
+CompositeFilterPtr castToCompositeFilter(AbstractFilterPtr from);
+
 }  // Tizen
 }  // DeviceAPI
 
index b082446..bd764dd 100644 (file)
@@ -58,12 +58,12 @@ class ChangeListenerContainer::ChangeListeners {
 
     for (auto& it : groups_) {
       if (it.second->Remove(id)) {
-        LoggerD("Listener with id: %d removed from group: %d", id, it.first);
+        LoggerD("Listener with id: %ld removed from group: %d", id, it.first);
         return;
       }
     }
 
-    LoggerW("WatchId %d not found", id);
+    LoggerW("WatchId %ld not found", id);
   }
 
   template <class CallbackType, class EventType>
@@ -155,11 +155,11 @@ class ChangeListenerContainer::ChangeListeners {
       bool ret = false;
 
       if (true == (ret = message_callbacks_.Remove(id))) {
-        LoggerD("Message listener with id: %d removed", id);
+        LoggerD("Message listener with id: %ld removed", id);
       } else if (true == (ret = conversation_callbacks_.Remove(id))) {
-        LoggerD("Conversation listener with id: %d removed", id);
+        LoggerD("Conversation listener with id: %ld removed", id);
       } else if (true == (ret = folder_callbacks_.Remove(id))) {
-        LoggerD("Folder listener with id: %d removed", id);
+        LoggerD("Folder listener with id: %ld removed", id);
       }
 
       return ret;
index 85608c1..aeec4e2 100644 (file)
@@ -315,10 +315,10 @@ void EmailManager::addDraftMessage(MessageCallbackUserData* callback) {
 }
 
 //**** sending email ****
-static gboolean sendEmailCompleteCB(void* data) {
+static gboolean sendEmailCompleteCB(void* user_data) {
   ScopeLogger();
 
-  MessageRecipientsCallbackData* callback = static_cast<MessageRecipientsCallbackData*>(data);
+  MessageRecipientsCallbackData* callback = static_cast<MessageRecipientsCallbackData*>(user_data);
   if (!callback) {
     LoggerE("Callback is null");
     return false;
@@ -896,7 +896,7 @@ void EmailManager::removeMessages(MessagesCallbackUserData* callback) {
 
   PlatformResult ret = RemoveMessagesPlatform(callback);
   if (ret.IsError()) {
-    LoggerE("%d (%s)", ret.error_code(), (ret.message()).c_str());
+    LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
     callback->SetError(ret);
     removeEmailCompleteCB(callback);
   }
@@ -974,7 +974,7 @@ void EmailManager::updateMessages(MessagesCallbackUserData* callback) {
 
   PlatformResult ret = UpdateMessagesPlatform(callback);
   if (ret.IsError()) {
-    LoggerE("%d (%s)", ret.error_code(), (ret.message()).c_str());
+    LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
     callback->SetError(ret);
   }
 
@@ -1042,7 +1042,7 @@ void EmailManager::findMessages(FindMsgCallbackUserData* callback) {
 
   PlatformResult ret = FindMessagesPlatform(callback);
   if (ret.IsError()) {
-    LoggerE("%d (%s)", ret.error_code(), (ret.message()).c_str());
+    LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
     callback->SetError(ret);
   }
 
@@ -1098,7 +1098,7 @@ void EmailManager::findConversations(ConversationCallbackData* callback) {
 
   PlatformResult ret = FindConversationsPlatform(callback);
   if (ret.IsError()) {
-    LoggerE("%d (%s)", ret.error_code(), (ret.message()).c_str());
+    LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
     callback->SetError(ret);
   }
 
@@ -1217,7 +1217,7 @@ void EmailManager::findFolders(FoldersCallbackData* callback) {
 
   PlatformResult ret = FindFoldersPlatform(callback);
   if (ret.IsError()) {
-    LoggerE("%d (%s)", ret.error_code(), (ret.message()).c_str());
+    LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
     callback->SetError(ret);
   }
 
@@ -1299,7 +1299,7 @@ void EmailManager::removeConversations(ConversationCallbackData* callback) {
 
   PlatformResult ret = RemoveConversationsPlatform(callback);
   if (ret.IsError()) {
-    LoggerE("%d (%s)", ret.error_code(), (ret.message()).c_str());
+    LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
     callback->SetError(ret);
   }
 
index 15935d0..80825fa 100644 (file)
@@ -1185,7 +1185,8 @@ PlatformResult Message::setMMSBodyAndAttachmentsFromStruct(Message* message, msg
 
               LoggerD("Loaded body: %s", message->getBody()->getPlainBody().c_str());
             } else {
-              LoggerE("Unhandled error: %d (%s)!", ret.error_code(), ret.message().c_str());
+              LoggerE("Unhandled error: %d (%s)!", static_cast<int>(ret.error_code()),
+                      ret.message().c_str());
               LoggerD("[p:%d, m:%d] body is not set", p, m);
             }
           } else {
@@ -1448,25 +1449,26 @@ PlatformResult Message::convertPlatformShortMessageToObject(msg_struct_t msg,
             MessagingUtil::messageStatusToString(msg_status).c_str());
   } else {
     LoggerE("Couldn't get MSG_MESSAGE_FOLDER_ID_INT, error:%d", error);
-    error = msg_get_int_value(msg, MSG_SENT_STATUS_NETWORK_STATUS_INT, &infoInt);
+    int info_network = MSG_NETWORK_NOT_SEND;
+    error = msg_get_int_value(msg, MSG_SENT_STATUS_NETWORK_STATUS_INT, &info_network);
 
     if (MSG_SUCCESS == error) {
       MessageStatus msg_status;
-      if (infoInt == MSG_NETWORK_SEND_SUCCESS) {
+      if (MSG_NETWORK_SEND_SUCCESS == info_network) {
         msg_status = MessageStatus::STATUS_SENT;
-      } else if (infoInt == MSG_NETWORK_SENDING) {
+      } else if (MSG_NETWORK_SENDING == info_network) {
         msg_status = MessageStatus::STATUS_SENDING;
-      } else if (infoInt == MSG_NETWORK_SEND_FAIL) {
+      } else if (MSG_NETWORK_SEND_FAIL == info_network) {
         msg_status = MessageStatus::STATUS_FAILED;
-      } else if (infoInt == MSG_NETWORK_NOT_SEND) {
+      } else if (MSG_NETWORK_NOT_SEND == info_network) {
         msg_status = MessageStatus::STATUS_DRAFT;
       } else {
-        LoggerW("warning undefined messageStatus: %d!", infoInt);
+        LoggerW("warning undefined messageStatus: %d!", info_network);
         msg_status = MessageStatus::STATUS_UNDEFINED;
       }
       message->setMessageStatus(msg_status);
 
-      LoggerD("MSG_SENT_STATUS_NETWORK_STATUS:%d MessageStatus:%s", infoInt,
+      LoggerD("MSG_SENT_STATUS_NETWORK_STATUS:%d MessageStatus:%s", info_network,
               MessagingUtil::messageStatusToString(msg_status).c_str());
     } else {
       LoggerE("Couldn't get MSG_SENT_STATUS_NETWORK_STATUS_INT, error:%d", error);
@@ -1684,7 +1686,7 @@ bool Message::isMatchingAttribute(const std::string& attribute_name,
 
 bool Message::isMatchingAttributeRange(const std::string& attribute_name, AnyPtr initial_value,
                                        AnyPtr end_value) const {
-  ScopeLogger(attribute_name);
+  ScopeLogger("attribute name: %s", attribute_name.c_str());
 
   using namespace MESSAGE_FILTER_ATTRIBUTE;
   if (TIMESTAMP == attribute_name) {
index 4644b29..168ebaf 100644 (file)
@@ -486,7 +486,7 @@ bool MessageConversation::isMatchingAttribute(const std::string& attribute_name,
 
 bool MessageConversation::isMatchingAttributeRange(const std::string& attribute_name,
                                                    AnyPtr initial_value, AnyPtr end_value) const {
-  ScopeLogger("attribute_name: " + attribute_name);
+  ScopeLogger("attribute_name: %s", attribute_name.c_str());
 
   using namespace CONVERSATION_FILTER_ATTRIBUTE;
 
index 9a8a874..ac15312 100644 (file)
@@ -47,7 +47,7 @@ static gboolean sendMessageTask(void* data) {
   auto ret = callback->getEmailManager().sendMessage(callback);
 
   if (!ret) {
-    LoggerE("Error: %d - %s", ret.error_code(), ret.message().c_str());
+    LoggerE("Error: %d - %s", static_cast<int>(ret.error_code()), ret.message().c_str());
   }
 
   return FALSE;
@@ -116,7 +116,7 @@ static gboolean loadMessageAttachmentTask(void* data) {
       const auto ret = callback->getEmailManager().loadMessageAttachment(callback);
 
       if (!ret) {
-        LoggerE("Error: %d - %s", ret.error_code(), ret.message().c_str());
+        LoggerE("Error: %d - %s", static_cast<int>(ret.error_code()), ret.message().c_str());
       }
     }
   } else {
index a5ca744..235b483 100644 (file)
@@ -54,7 +54,7 @@ static gboolean sendMessageThread(void* data) {
   auto ret = callback->getShortMsgManager().sendMessage(callback);
 
   if (!ret) {
-    LoggerE("Error: %d - %s", ret.error_code(), ret.message().c_str());
+    LoggerE("Error: %d - %s", static_cast<int>(ret.error_code()), ret.message().c_str());
   }
 
   return FALSE;
index d476d9c..e0567dc 100644 (file)
@@ -81,17 +81,17 @@ MessagePtrVector MessagesChangeCallback::filterMessages(tizen::AbstractFilterPtr
       }
 
       LoggerD("[%d] is Message(%p) {", i, message.get());
-      LoggerD("[%d] messageId: %d", i, message->getId());
-      LoggerD("[%d] message subject: %s", i, message->getSubject().c_str());
-      LoggerD("[%d] from: %s", i, message->getFrom().c_str());
+      LoggerD("messageId: %d", message->getId());
+      LoggerD("message subject: %s", message->getSubject().c_str());
+      LoggerD("from: %s", message->getFrom().c_str());
 
       if (message->getBody()) {
         const std::string& pBody = message->getBody()->getPlainBody();
-        LoggerD("[%d] message plainBody: %s", i, limitedString(pBody).c_str());
+        LoggerD("message plainBody: %s", limitedString(pBody).c_str());
       }
 
-      LoggerD("[%d] matched filter: %s", i, matched ? "YES" : "NO");
-      LoggerD("[%d] }");
+      LoggerD("matched filter: %s", matched ? "YES" : "NO");
+      LoggerD("}");
     }
 
     LoggerD("returning matching %d of %d messages", filtered_messages.size(),
index 6d87bd2..711252e 100644 (file)
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+#include <iterator>
 #include <sstream>
 
 #include <email-api.h>
@@ -180,9 +181,9 @@ msg_error_t MessagingDatabaseManager::connect() {
       return MSG_ERR_DB_CONNECT;
     }
 
-    LoggerD("DB connecting success: [%d]", sqlHandle);
+    LoggerD("DB connecting success: [%p]", sqlHandle);
   } else {
-    LoggerD("DB connection exists: [%d]", sqlHandle);
+    LoggerD("DB connection exists: [%p]", sqlHandle);
   }
 
   return MSG_SUCCESS;
@@ -451,7 +452,7 @@ PlatformResult MessagingDatabaseManager::getAttributeFilterQuery(AbstractFilterP
           break;
 
         default:
-          LoggerE("Unexpected folder ID: %d", folder_id);
+          LoggerE("Unexpected folder ID: %ld", static_cast<long>(folder_id));
           folder_id = -1;
           break;
       }
@@ -900,9 +901,9 @@ void sortConversations(const SortMode& sortMode, ConversationPtrVector* conversa
   auto comparator = MessageConversation::getComparator(attribute);
 
   if (SortModeOrder::ASC == sortMode.getOrder()) {
-    std::sort(conversations->begin(), conversations->end(), comparator);
+    std::sort(std::begin(*conversations), std::end(*conversations), comparator);
   } else {
-    std::sort(conversations->rbegin(), conversations->rend(), comparator);
+    std::sort(std::rbegin(*conversations), std::rend(*conversations), comparator);
   }
 }
 
index c10c2ff..5ab5573 100644 (file)
@@ -22,7 +22,9 @@
 
 #include <db-util.h>
 #include <msg.h>
-#include "MsgCommon/AbstractFilter.h"
+#include "MsgCommon/AttributeFilter.h"
+#include "MsgCommon/AttributeRangeFilter.h"
+#include "MsgCommon/CompositeFilter.h"
 
 #include "common/platform_result.h"
 #include "find_msg_callback_user_data.h"
index 875844b..5884f0d 100644 (file)
@@ -1011,14 +1011,14 @@ PlatformResult MessagingUtil::jsonFilterToCompositeFilter(const picojson::object
   auto compositeFilter = new CompositeFilter(filterType);
 
   for (const auto& a : filter.at(JSON_TO_FILTER_ARRAY).get<picojson::array>()) {
-    AbstractFilterPtr filter;
-    PlatformResult ret = jsonFilterToAbstractFilter(a.get<picojson::object>(), &filter);
+    AbstractFilterPtr filter_ptr;
+    PlatformResult ret = jsonFilterToAbstractFilter(a.get<picojson::object>(), &filter_ptr);
     if (ret.IsError()) {
       delete compositeFilter;
       LoggerD("Convert JSON filter to Abstract filter failed (%s)", ret.message().c_str());
       return ret;
     }
-    compositeFilter->addFilter(filter);
+    compositeFilter->addFilter(filter_ptr);
   }
 
   (*result).reset(compositeFilter);
index 6af1d6c..a4c2cbd 100644 (file)
@@ -27,8 +27,9 @@
 #include "common/picojson.h"
 #include "common/platform_result.h"
 
-#include "MsgCommon/AbstractFilter.h"
 #include "MsgCommon/AttributeFilter.h"
+#include "MsgCommon/AttributeRangeFilter.h"
+#include "MsgCommon/CompositeFilter.h"
 #include "MsgCommon/SortMode.h"
 
 #include "common/platform_result.h"
index 6007a59..d1fc95c 100644 (file)
@@ -39,10 +39,10 @@ using common::PlatformResult;
 namespace extension {
 namespace messaging {
 
-static gboolean sendMessageCompleteCB(void* data) {
-  ScopeLogger("callback:%p", data);
+static gboolean sendMessageCompleteCB(void* user_data) {
+  ScopeLogger("callback: %p", user_data);
 
-  MessageRecipientsCallbackData* callback = static_cast<MessageRecipientsCallbackData*>(data);
+  MessageRecipientsCallbackData* callback = static_cast<MessageRecipientsCallbackData*>(user_data);
   if (!callback) {
     LoggerE("Callback is null");
     return false;
@@ -431,7 +431,7 @@ PlatformResult ShortMsgManager::callProperEventMessages(EventMessages* event,
             updated_conv.push_back(cur_conv);
           }
 
-          LoggerD("%s conversation with id:%d last_msg_id:d", (new_conv ? "ADDED" : "UPDATED"),
+          LoggerD("%s conversation with id:%d last_msg_id:%d", (new_conv ? "ADDED" : "UPDATED"),
                   cur_conv->getConversationId(), cur_conv->getLastMessageId());
         }
 
@@ -675,7 +675,7 @@ void ShortMsgManager::addDraftMessage(MessageCallbackUserData* callback) {
 
     PlatformResult ret = addDraftMessagePlatform(message);
     if (ret.IsError()) {
-      LoggerE("%d (%s)", ret.error_code(), ret.message().c_str());
+      LoggerE("%d (%s)", static_cast<int>(ret.error_code()), ret.message().c_str());
       callback->SetError(ret);
     }
   }
@@ -892,7 +892,8 @@ void ShortMsgManager::findMessages(FindMsgCallbackUserData* callback) {
     PlatformResult ret =
         MessagingDatabaseManager::getInstance().findShortMessages(callback, &messagesIds);
     if (ret.IsError()) {
-      LoggerE("Failed to find short message: %s (%d)", ret.message().c_str(), ret.error_code());
+      LoggerE("Failed to find short message: %s (%d)", ret.message().c_str(),
+              static_cast<int>(ret.error_code()));
       callback->SetError(ret);
     }
 
@@ -1090,7 +1091,7 @@ void ShortMsgManager::removeConversations(ConversationCallbackData* callback) {
                   "saved MessageConversation(%p) with conv_id:%d",
                   conv_index, msg_index, cur_msg_id, conv.get(), conv_id);
             } else {
-              LoggerE("[%d] Couldn't get msg_id, error: %d!", error);
+              LoggerE("[%d] Couldn't get msg_id, error: %s!", error, get_error_message(error));
             }
           }
         } else {
index 25b02f9..79597cd 100644 (file)
@@ -34,7 +34,7 @@
             'packages': [
                 'capi-system-info',
                 'capi-network-nfc',
-                'capi-appfw-application'
+                'capi-appfw-app-control',
             ]
           },
         }],
index 3a6f9eb..f1725f3 100644 (file)
@@ -65,7 +65,13 @@ void HCEEventCallback(nfc_se_h handle, nfc_hce_event_type_e event_type, unsigned
   // HCE Event Data
   picojson::value event_data = picojson::value(picojson::object());
   picojson::object& event_data_obj = event_data.get<picojson::object>();
-  event_data_obj[JSON_EVENT_TYPE] = picojson::value(NFCUtil::ToStr(event_type));
+  std::string event_type_str;
+  PlatformResult ret = NFCUtil::ToStr(event_type, &event_type_str);
+  if (!ret) {
+    LoggerE("ToStr method returned error. Error code: [%d]", (int)ret.error_code());
+    return;
+  }
+  event_data_obj[JSON_EVENT_TYPE] = picojson::value(event_type_str);
   event_data_obj[JSON_APDU] = picojson::value(NFCUtil::FromUCharArray(apdu, apdu_len));
   event_data_obj[JSON_LENGTH] = picojson::value(static_cast<double>(apdu_len));
   tools::ReportSuccess(event_data, response_obj);
@@ -89,6 +95,7 @@ NFCAdapter::NFCAdapter()
       m_is_ndef_listener_set(false),
       m_se_handle(nullptr),
       m_is_hce_listener_set(false),
+      m_is_preferred_app_set(false),
       responder_(nullptr) {
   ScopeLogger();
   // NFC library initialization
@@ -121,6 +128,9 @@ NFCAdapter::~NFCAdapter() {
   if (m_is_hce_listener_set) {
     nfc_manager_unset_hce_event_cb();
   }
+  if (m_is_preferred_app_set) {
+    nfc_se_unset_preferred_handler();
+  }
 
   // NFC library deinitialization
   int ret = nfc_manager_deinitialize();
@@ -137,7 +147,6 @@ void NFCAdapter::SetResponder(IResponder* responder) {
 void NFCAdapter::RespondAsync(const char* msg) {
   ScopeLogger();
   if (GetInstance()->responder_) {
-    AssertMsg(GetInstance()->responder_, "Handler variable should be set");
     GetInstance()->responder_->RespondAsync(msg);
   } else {
     LoggerE("Ignoring, instance does not exist");
@@ -610,7 +619,9 @@ PlatformResult NFCAdapter::RemoveTransactionEventListener(const picojson::value&
     nfc_manager_unset_se_transaction_event_cb(se_type);
     m_is_transaction_hce_listener_set = false;
   } else {
-    AssertMsg(false, "Invalid NFC SecureElement type");
+    return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "Invalid NFC SecureElement type",
+        ("NFC SecureElement type has not an expected value. Passed value is %d", (int)se_type));
   }
   return PlatformResult(ErrorCode::NO_ERROR);
 }
@@ -835,7 +846,7 @@ PlatformResult NFCAdapter::TagNDEFSizeGetter(int /*tag_id*/, unsigned int* size)
 
   int err = nfc_tag_get_ndef_size(m_last_tag_handle, size);
   if (NFC_ERROR_NONE != err) {
-    LoggerE("Failed to get tag NDEF size: %d, %s", err);
+    LoggerE("Failed to get tag NDEF size: %d, %s", err, get_error_message(err));
     return NFCUtil::CodeToResult(err, "Failed to get tag NDEF size");
   }
   return PlatformResult(ErrorCode::NO_ERROR);
@@ -1245,7 +1256,7 @@ PlatformResult NFCAdapter::GetCachedMessage(picojson::object& out) {
   PlatformResult ret = NFCMessageUtils::ReportNdefMessageFromData(raw_data, size, out);
   free(raw_data);
   if (ret.IsError()) {
-    LoggerE("Error: %d", ret.message().c_str());
+    LoggerE("Error: %s", ret.message().c_str());
     NFCMessageUtils::RemoveMessageHandle(message_handle);
     return ret;
   }
@@ -1381,8 +1392,10 @@ void NFCAdapter::SendHostAPDUResponse(const UCharVector& apdu,
 PlatformResult NFCAdapter::IsActivatedHandlerForAID(const std::string& type, const std::string& aid,
                                                     bool* is_activated_handler) {
   ScopeLogger();
-  AssertMsg(is_activated_handler, "Poiner can not be null!");
 
+  if (!is_activated_handler) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Pointer can not be null!");
+  }
   nfc_se_type_e se_type;
   PlatformResult result = NFCUtil::ToSecureElementType(type, &se_type);
   if (result.IsError()) {
@@ -1402,8 +1415,10 @@ PlatformResult NFCAdapter::IsActivatedHandlerForCategory(
     const std::string& type, nfc_card_emulation_category_type_e category,
     bool* is_activated_handler) {
   ScopeLogger();
-  AssertMsg(is_activated_handler, "Poiner can not be null!");
 
+  if (!is_activated_handler) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Pointer can not be null!");
+  }
   nfc_se_type_e se_type;
   PlatformResult result = NFCUtil::ToSecureElementType(type, &se_type);
   if (result.IsError()) {
@@ -1457,11 +1472,19 @@ PlatformResult NFCAdapter::UnregisterAID(const std::string& type, const std::str
 
 static void SaveRow(nfc_se_type_e se_type, const char* aid, bool read_only, void* user_data) {
   ScopeLogger();
-  AssertMsg(aid, "Poiner can not be null!");
-  AssertMsg(user_data, "Poiner can not be null!");
+  if (!aid || !user_data) {
+    LoggerE("Aid or user_data are empty. Returning");
+    return;
+  }
   AIDDataVector* aids = static_cast<AIDDataVector*>(user_data);
   std::string aid_str = std::string(aid);
-  aids->push_back(AIDData(std::string(NFCUtil::ToStr(se_type)), aid_str, read_only));
+  std::string se_type_str;
+  PlatformResult ret = NFCUtil::ToStr(se_type, &se_type_str);
+  if (!ret) {
+    LoggerE("ToStr method returned error. Error code: [%d]", (int)ret.error_code());
+    return;
+  }
+  aids->push_back(AIDData(se_type_str, aid_str, read_only));
 };
 
 void NFCAdapter::GetAIDsForCategory(const std::string& type,
@@ -1486,5 +1509,80 @@ void NFCAdapter::GetAIDsForCategory(const std::string& type,
   success_cb(aids);
 }
 
+PlatformResult NFCAdapter::SetPreferredApp() {
+  ScopeLogger("m_is_preferred_app_set: %d", m_is_preferred_app_set);
+
+  if (m_is_preferred_app_set) {
+    return PlatformResult(ErrorCode::NO_ERROR);
+  }
+  bool is_activated_handler = false;
+
+  // check whether app has any activated handler for payment category
+  // if yes, there is no need of calling nfc_se_set_preferred_handler
+  std::vector<nfc_se_type_e> nfc_ce_types{NFC_SE_TYPE_ESE, NFC_SE_TYPE_UICC, NFC_SE_TYPE_HCE};
+  LoggerD(
+      "Checking for activated handlers using "
+      "nfc_se_is_activated_handler_for_category");
+  for (auto type : nfc_ce_types) {
+    int ret = nfc_se_is_activated_handler_for_category(type, NFC_CARD_EMULATION_CATEGORY_PAYMENT,
+                                                       &is_activated_handler);
+    if (NFC_ERROR_NONE != ret) {
+      LoggerE("nfc_se_is_activated_handler_for_category failed: %d, type: %d", ret, (int)type);
+      return NFCUtil::CodeToResult(ret, NFCUtil::getNFCErrorMessage(ret).c_str());
+    }
+    if (is_activated_handler) {
+      LoggerD("App is an activated hadler, no need of calling nfc_se_set_preferred_handler");
+      return PlatformResult(ErrorCode::NO_ERROR);
+    }
+  }
+
+  // if there is no activated handler we need to ensure
+  // that there is at least one registered AID
+  LoggerD("Checking for registered AIDs");
+  AIDDataVector aids{};
+  for (auto type : nfc_ce_types) {
+    int ret =
+        nfc_se_foreach_registered_aids(type, NFC_CARD_EMULATION_CATEGORY_PAYMENT, SaveRow, &aids);
+    if (NFC_ERROR_NONE != ret) {
+      LoggerE("nfc_se_foreach_registered_aids failed: %d, type: %d", ret, (int)type);
+      return NFCUtil::CodeToResult(ret, NFCUtil::getNFCErrorMessage(ret).c_str());
+    }
+    if (!aids.empty()) {
+      break;
+    }
+  }
+  if (aids.empty()) {
+    return LogAndCreateResult(ErrorCode::ABORT_ERR, "No AID registered");
+  }
+  LoggerD("Found %d AIDs", aids.size());
+
+  int ret = nfc_se_set_preferred_handler();
+  if (ret != NFC_ERROR_NONE) {
+    LoggerE("nfc_se_set_preferred_handler failed: %d", ret);
+    return NFCUtil::CodeToResult(ret, NFCUtil::getNFCErrorMessage(ret).c_str(), true);
+  }
+  m_is_preferred_app_set = true;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult NFCAdapter::UnsetPreferredApp() {
+  ScopeLogger();
+
+  if (!m_is_preferred_app_set) {
+    return PlatformResult(ErrorCode::NO_ERROR);
+  }
+
+  int ret = nfc_se_unset_preferred_handler();
+  if (ret != NFC_ERROR_NONE) {
+    LoggerE("nfc_se_unset_preferred_handler failed: %d", ret);
+    return NFCUtil::CodeToResult(ret, NFCUtil::getNFCErrorMessage(ret).c_str(), true);
+  }
+
+  m_is_preferred_app_set = false;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
 }  // nfc
 }  // extension
index 791453e..8e7c1b0 100644 (file)
@@ -117,6 +117,8 @@ class NFCAdapter {
   void GetAIDsForCategory(const std::string& type, nfc_card_emulation_category_type_e category,
                           const std::function<void(const AIDDataVector&)>& success_cb,
                           const std::function<void(const common::PlatformResult&)>& error_cb);
+  common::PlatformResult SetPreferredApp();
+  common::PlatformResult UnsetPreferredApp();
 
  private:
   NFCAdapter();
@@ -135,6 +137,7 @@ class NFCAdapter {
   bool m_is_ndef_listener_set;
   nfc_se_h m_se_handle;
   bool m_is_hce_listener_set;
+  bool m_is_preferred_app_set;
 
   IResponder* responder_;
 };
index d8e9553..5eef7c2 100644 (file)
@@ -153,6 +153,7 @@ var transactionEventListenerUicc = new ListenerManager(
     TRANSACTION_EVENT_UICC_LISTENER
 );
 var HCEEventListener = new ListenerManager(native_, HCE_EVENT_LISTENER);
+var isWebkitVisibilityChangeListenerSet = false;
 
 //////////////////NFCManager /////////////////
 
@@ -273,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, [
@@ -948,6 +949,51 @@ NFCAdapter.prototype.getAIDsForCategory = function(
     }
 };
 
+function WebkitVisibilityChangeListener() {
+    var result;
+    if (true === privUtils_.global.document.hidden) {
+        result = native_.call('NFCAdapter_unsetPreferredApp');
+    } else if (false === privUtils_.global.document.hidden) {
+        result = native_.call('NFCAdapter_setPreferredApp');
+    }
+
+    if (native_.isFailure(result)) {
+        privUtils_.log('Failed to (un)set: ' + result.error.message);
+    }
+}
+
+NFCAdapter.prototype.setPreferredApp = function() {
+    var result = native_.call('NFCAdapter_setPreferredApp');
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    } else {
+        if (false === isWebkitVisibilityChangeListenerSet) {
+            privUtils_.global.document.addEventListener(
+                'webkitvisibilitychange',
+                WebkitVisibilityChangeListener
+            );
+            isWebkitVisibilityChangeListenerSet = true;
+        }
+    }
+};
+
+NFCAdapter.prototype.unsetPreferredApp = function() {
+    var result = native_.call('NFCAdapter_unsetPreferredApp');
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    } else {
+        if (true === isWebkitVisibilityChangeListenerSet) {
+            privUtils_.global.document.removeEventListener(
+                'webkitvisibilitychange',
+                WebkitVisibilityChangeListener
+            );
+            isWebkitVisibilityChangeListenerSet = false;
+        }
+    }
+};
+
 function InternalRecordData(tnf, type, payload, id) {
     this.tnf = tnf;
     this.type = type;
index 70c5dcc..4344397 100644 (file)
@@ -112,6 +112,8 @@ NFCInstance::NFCInstance() {
   REGISTER_SYNC("NFCAdapter_registerAID", RegisterAID);
   REGISTER_SYNC("NFCAdapter_unregisterAID", UnregisterAID);
   REGISTER_ASYNC("NFCAdapter_getAIDsForCategory", GetAIDsForCategory);
+  REGISTER_SYNC("NFCAdapter_setPreferredApp", SetPreferredApp);
+  REGISTER_SYNC("NFCAdapter_unsetPreferredApp", UnsetPreferredApp);
 
   REGISTER_SYNC("NFCPeer_setReceiveNDEFListener", SetReceiveNDEFListener);
   REGISTER_SYNC("NFCPeer_unsetReceiveNDEFListener", UnsetReceiveNDEFListener);
@@ -899,11 +901,16 @@ void NFCInstance::IsActivatedHandlerForCategory(const picojson::value& args,
   CHECK_EXIST(args, JSON_TYPE, out);
   CHECK_EXIST(args, JSON_CATEGORY, out);
 
-  nfc_card_emulation_category_type_e category =
-      NFCUtil::StringToCategory(args.get(JSON_CATEGORY).get<std::string>());
+  nfc_card_emulation_category_type_e category;
+  PlatformResult result =
+      NFCUtil::StringToCategory(args.get(JSON_CATEGORY).get<std::string>(), &category);
+  if (result.IsError()) {
+    LogAndReportError(result, &out);
+    return;
+  }
   bool is_activated_handler = false;
 
-  PlatformResult result = NFCAdapter::GetInstance()->IsActivatedHandlerForCategory(
+  result = NFCAdapter::GetInstance()->IsActivatedHandlerForCategory(
       args.get(JSON_TYPE).get<std::string>(), category, &is_activated_handler);
   if (result.IsSuccess()) {
     ReportSuccess(picojson::value(is_activated_handler), out);
@@ -920,11 +927,16 @@ void NFCInstance::RegisterAID(const picojson::value& args, picojson::object& out
   CHECK_EXIST(args, JSON_AID, out);
   CHECK_EXIST(args, JSON_CATEGORY, out);
 
-  nfc_card_emulation_category_type_e category =
-      NFCUtil::StringToCategory(args.get(JSON_CATEGORY).get<std::string>());
+  nfc_card_emulation_category_type_e category;
+  PlatformResult result =
+      NFCUtil::StringToCategory(args.get(JSON_CATEGORY).get<std::string>(), &category);
+  if (result.IsError()) {
+    LogAndReportError(result, &out);
+    return;
+  }
 
-  PlatformResult result = NFCAdapter::GetInstance()->RegisterAID(
-      args.get(JSON_TYPE).get<std::string>(), args.get(JSON_AID).get<std::string>(), category);
+  result = NFCAdapter::GetInstance()->RegisterAID(args.get(JSON_TYPE).get<std::string>(),
+                                                  args.get(JSON_AID).get<std::string>(), category);
   if (result.IsSuccess()) {
     ReportSuccess(out);
   } else {
@@ -939,11 +951,15 @@ void NFCInstance::UnregisterAID(const picojson::value& args, picojson::object& o
   CHECK_EXIST(args, JSON_TYPE, out);
   CHECK_EXIST(args, JSON_AID, out);
   CHECK_EXIST(args, JSON_CATEGORY, out);
+  nfc_card_emulation_category_type_e category;
+  PlatformResult result =
+      NFCUtil::StringToCategory(args.get(JSON_CATEGORY).get<std::string>(), &category);
+  if (result.IsError()) {
+    LogAndReportError(result, &out);
+    return;
+  }
 
-  nfc_card_emulation_category_type_e category =
-      NFCUtil::StringToCategory(args.get(JSON_CATEGORY).get<std::string>());
-
-  PlatformResult result = NFCAdapter::GetInstance()->UnregisterAID(
+  result = NFCAdapter::GetInstance()->UnregisterAID(
       args.get(JSON_TYPE).get<std::string>(), args.get(JSON_AID).get<std::string>(), category);
   if (result.IsSuccess()) {
     ReportSuccess(out);
@@ -959,8 +975,13 @@ void NFCInstance::GetAIDsForCategory(const picojson::value& args, picojson::obje
   CHECK_EXIST(args, JSON_TYPE, out);
   CHECK_EXIST(args, JSON_CATEGORY, out);
   const std::string& type = args.get(JSON_TYPE).get<std::string>();
-  nfc_card_emulation_category_type_e required_category =
-      NFCUtil::StringToCategory(args.get(JSON_CATEGORY).get<std::string>());
+  nfc_card_emulation_category_type_e required_category;
+  PlatformResult result =
+      NFCUtil::StringToCategory(args.get(JSON_CATEGORY).get<std::string>(), &required_category);
+  if (result.IsError()) {
+    LogAndReportError(result, &out);
+    return;
+  }
   const double& callback_id = args.get(JSON_CALLBACK_ID).get<double>();
 
   auto success_cb = [this, callback_id](const AIDDataVector& data) -> void {
@@ -991,5 +1012,29 @@ void NFCInstance::GetAIDsForCategory(const picojson::value& args, picojson::obje
                                                    required_category, success_cb, error_cb));
 }
 
+void NFCInstance::SetPreferredApp(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeNfcCardEmulation, &out);
+
+  PlatformResult result = NFCAdapter::GetInstance()->SetPreferredApp();
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void NFCInstance::UnsetPreferredApp(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeNfcCardEmulation, &out);
+
+  PlatformResult result = NFCAdapter::GetInstance()->UnsetPreferredApp();
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
 }  // namespace nfc
 }  // namespace extension
index b23c517..73fd71e 100644 (file)
@@ -84,6 +84,8 @@ class NFCInstance : public common::ParsedInstance, NFCAdapter::IResponder {
   void RegisterAID(const picojson::value& args, picojson::object& out);
   void UnregisterAID(const picojson::value& args, picojson::object& out);
   void GetAIDsForCategory(const picojson::value& args, picojson::object& out);
+  void SetPreferredApp(const picojson::value& args, picojson::object& out);
+  void UnsetPreferredApp(const picojson::value& args, picojson::object& out);
 };
 
 }  // namespace nfc
index 1e36a2f..f231cf8 100644 (file)
@@ -315,8 +315,11 @@ static PlatformResult NdefRecordGetHandle(picojson::value& record,
     return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "Record is empty");
   }
   const picojson::object& record_obj = record.get<picojson::object>();
-  short tnf_from_json = static_cast<short>(record.get("tnf").get<double>());
-  nfc_record_tnf_e tnf = static_cast<nfc_record_tnf_e>(tnf_from_json);
+  int tnf_from_json = static_cast<int>(record.get("tnf").get<double>());
+  if ((tnf_from_json < TNF_MIN) || (tnf_from_json > TNF_MAX)) {
+    return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "Type mismatch", ("Not supported TNF"));
+  }
+  nfc_record_tnf_e tnf = static_cast<nfc_record_tnf_e>(static_cast<unsigned int>(tnf_from_json));
   const picojson::array& type_data = FromJson<picojson::array>(record_obj, "type");
   auto type_size = type_data.size();
   std::unique_ptr<unsigned char[]> type(new unsigned char[type_size]);
@@ -335,9 +338,6 @@ static PlatformResult NdefRecordGetHandle(picojson::value& record,
   for (size_t i = 0; i < payload_size; i++) {
     payload[i] = (int)payload_data[i].get<double>();
   }
-  if ((tnf_from_json < TNF_MIN) || (tnf_from_json > TNF_MAX)) {
-    return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "Type mismatch", ("Not supported TNF"));
-  }
   const int BYTE_ARRAY_MAX = 255;
   nfc_ndef_record_h ndef_record_handle = NULL;
   int result = nfc_ndef_record_create(
index fcfb13e..de51aaa 100644 (file)
@@ -32,7 +32,8 @@ UCharVector NFCUtil::ToVector(const unsigned char* ch, const int size) {
   return vec;
 }
 
-PlatformResult NFCUtil::CodeToResult(const int errorCode, const std::string& message) {
+PlatformResult NFCUtil::CodeToResult(const int errorCode, const std::string& message,
+                                     const bool newAPIVersion) {
   ScopeLogger();
   switch (errorCode) {
     case NFC_ERROR_INVALID_PARAMETER:
@@ -54,7 +55,11 @@ PlatformResult NFCUtil::CodeToResult(const int errorCode, const std::string& mes
     case NFC_ERROR_OUT_OF_MEMORY:
     case NFC_ERROR_NOT_INITIALIZED:
     default:
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, message);
+      if (newAPIVersion) {
+        return LogAndCreateResult(ErrorCode::ABORT_ERR, message);
+      } else {
+        return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, message);
+      }
   }
 }
 
@@ -290,46 +295,68 @@ void NFCUtil::setDefaultFilterValues(std::vector<nfc_tag_type_e>& filter) {
 }
 
 // Convertion of enum to HCEEventType(characters sequence).
-const char* NFCUtil::ToStr(nfc_hce_event_type_e event_type) {
+PlatformResult NFCUtil::ToStr(nfc_hce_event_type_e event_type, std::string* result_type) {
   ScopeLogger();
   switch (event_type) {
     case NFC_HCE_EVENT_DEACTIVATED:
-      return "DEACTIVATED";
+      *result_type = "DEACTIVATED";
+      break;
     case NFC_HCE_EVENT_ACTIVATED:
-      return "ACTIVATED";
+      *result_type = "ACTIVATED";
+      break;
     case NFC_HCE_EVENT_APDU_RECEIVED:
-      return "APDU_RECEIVED";
+      *result_type = "APDU_RECEIVED";
+      break;
     default:
-      AssertMsg(false, "That event type is incorrect.");
+      return LogAndCreateResult(
+          ErrorCode::UNKNOWN_ERR, "That event type is incorrect.",
+          ("Event has not an expected value. Passed value is %d", (int)event_type));
   }
+  return PlatformResult(ErrorCode::NO_ERROR);
 }
 
 // Convertion of enum to SecureElementType(characters sequence).
 // Warning! DISABLE and SDCARD are not mentioned at widl spec.
-const char* NFCUtil::ToStr(nfc_se_type_e se_type) {
+PlatformResult NFCUtil::ToStr(nfc_se_type_e se_type, std::string* result_type) {
   ScopeLogger();
   switch (se_type) {
     case NFC_SE_TYPE_DISABLE:
-      return "DISABLE";
+      *result_type = "DISABLE";
+      break;
     case NFC_SE_TYPE_ESE:
-      return "ESE";
+      *result_type = "ESE";
+      break;
     case NFC_SE_TYPE_UICC:
-      return "UICC";
+      *result_type = "UICC";
+      break;
     case NFC_SE_TYPE_SDCARD:
-      return "SDCARD";
+      *result_type = "SDCARD";
+      break;
     case NFC_SE_TYPE_HCE:
-      return "HCE";
+      *result_type = "HCE";
+      break;
     default:
-      AssertMsg(false, "That event type is incorrect.");
+      return LogAndCreateResult(
+          ErrorCode::UNKNOWN_ERR, "That event type is incorrect.",
+          ("Event has not an expected value. Passed value is %d", (int)se_type));
   }
+  return PlatformResult(ErrorCode::NO_ERROR);
 }
 
 // Convertion CardEmulationCategoryType(characters sequence) to enum.
-nfc_card_emulation_category_type_e NFCUtil::StringToCategory(const std::string& category_type) {
+PlatformResult NFCUtil::StringToCategory(const std::string& category_type,
+                                         nfc_card_emulation_category_type_e* result_type) {
   ScopeLogger();
-  if (category_type == "PAYMENT") return NFC_CARD_EMULATION_CATEGORY_PAYMENT;
-  if (category_type == "OTHER") return NFC_CARD_EMULATION_CATEGORY_OTHER;
-  AssertMsg(false, "That category type is incorrect.");
+  if (category_type == "PAYMENT") {
+    *result_type = NFC_CARD_EMULATION_CATEGORY_PAYMENT;
+  } else if (category_type == "OTHER") {
+    *result_type = NFC_CARD_EMULATION_CATEGORY_OTHER;
+  } else {
+    return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "That category type is incorrect.",
+        ("Category has not an expected value. Passed value is %s", category_type.c_str()));
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
 }
 
 unsigned char* NFCUtil::DoubleArrayToUCharArray(const picojson::array& array_in) {
index 1e806c2..b3f8039 100644 (file)
@@ -60,7 +60,8 @@ typedef std::vector<unsigned char> UCharVector;
 class NFCUtil {
  public:
   static UCharVector ToVector(const unsigned char* ch, const int size);
-  static common::PlatformResult CodeToResult(const int errorCode, const std::string& message);
+  static common::PlatformResult CodeToResult(const int errorCode, const std::string& message,
+                                             const bool newAPIVersion = false);
   static std::string getNFCErrorString(const int error_code);
   static const std::string getNFCErrorMessage(const int error_code);
   static std::string ToStringNFCTag(const nfc_tag_type_e tag_type);
@@ -75,9 +76,10 @@ class NFCUtil {
   static common::PlatformResult ToSecureElementType(const std::string& type_string,
                                                     nfc_se_type_e* type);
   static void setDefaultFilterValues(std::vector<nfc_tag_type_e>& filter);
-  static const char* ToStr(nfc_hce_event_type_e event_type);
-  static const char* ToStr(nfc_se_type_e se_type);
-  static nfc_card_emulation_category_type_e StringToCategory(const std::string& category_type);
+  static common::PlatformResult ToStr(nfc_hce_event_type_e event_type, std::string* result_type);
+  static common::PlatformResult ToStr(nfc_se_type_e se_type, std::string* result_type);
+  static common::PlatformResult StringToCategory(const std::string& category_type,
+                                                 nfc_card_emulation_category_type_e* result_type);
   static unsigned char* DoubleArrayToUCharArray(const picojson::array& array_in);
   static UCharVector DoubleArrayToUCharVector(const picojson::array& array_in);
   static picojson::array FromUCharArray(unsigned char* array, unsigned int apdu_len);
diff --git a/src/notification/common_notification.cc b/src/notification/common_notification.cc
new file mode 100644 (file)
index 0000000..52cc10b
--- /dev/null
@@ -0,0 +1,1369 @@
+/*
+ * Copyright (c) 2015-2017 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 "notification/common_notification.h"
+
+#include <app_control_internal.h>
+#include <notification_internal.h>
+
+#include "common/converter.h"
+#include "common/filesystem/filesystem_provider.h"
+#include "common/logger.h"
+#include "common/scope_exit.h"
+
+namespace extension {
+namespace notification {
+
+using namespace common;
+
+const InformationEnumMap CommonNotification::info_map_ = {{0, NOTIFICATION_TEXT_TYPE_INFO_1},
+                                                          {1, NOTIFICATION_TEXT_TYPE_INFO_2},
+                                                          {2, NOTIFICATION_TEXT_TYPE_INFO_3}};
+
+const InformationEnumMap CommonNotification::info_sub_map_ = {
+    {0, NOTIFICATION_TEXT_TYPE_INFO_SUB_1},
+    {1, NOTIFICATION_TEXT_TYPE_INFO_SUB_2},
+    {2, NOTIFICATION_TEXT_TYPE_INFO_SUB_3}};
+
+const ImageEnumMap CommonNotification::thumbnails_map_ = {{0, NOTIFICATION_IMAGE_TYPE_LIST_1},
+                                                          {1, NOTIFICATION_IMAGE_TYPE_LIST_2},
+                                                          {2, NOTIFICATION_IMAGE_TYPE_LIST_3},
+                                                          {3, NOTIFICATION_IMAGE_TYPE_LIST_4}};
+
+const InformationEnumMap CommonNotification::buttons_texts_map_ = {
+    {0, NOTIFICATION_TEXT_TYPE_BUTTON_1}, {1, NOTIFICATION_TEXT_TYPE_BUTTON_2},
+    {2, NOTIFICATION_TEXT_TYPE_BUTTON_3}, {3, NOTIFICATION_TEXT_TYPE_BUTTON_4},
+    {4, NOTIFICATION_TEXT_TYPE_BUTTON_5}, {5, NOTIFICATION_TEXT_TYPE_BUTTON_6}};
+
+const ImageEnumMap CommonNotification::buttons_icon_paths_map_ = {
+    {0, NOTIFICATION_IMAGE_TYPE_BUTTON_1}, {1, NOTIFICATION_IMAGE_TYPE_BUTTON_2},
+    {2, NOTIFICATION_IMAGE_TYPE_BUTTON_3}, {3, NOTIFICATION_IMAGE_TYPE_BUTTON_4},
+    {4, NOTIFICATION_IMAGE_TYPE_BUTTON_5}, {5, NOTIFICATION_IMAGE_TYPE_BUTTON_6}};
+
+CommonNotification::CommonNotification() {
+}
+
+CommonNotification::~CommonNotification() {
+}
+
+bool CommonNotification::IsColorFormatNumeric(const std::string& color) {
+  ScopeLogger();
+  std::string hexCode = "0123456789abcdef";
+  if (7 != color.length() || '#' != color[0]) {
+    return false;
+  }
+
+  for (size_t i = 1; i < color.length(); i++) {
+    if (hexCode.find(color[i]) == std::string::npos) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+PlatformResult CommonNotification::SetLayout(notification_h noti_handle,
+                                             const std::string& noti_type) {
+  ScopeLogger();
+  notification_ly_type_e noti_layout = NOTIFICATION_LY_NONE;
+
+  if ("SIMPLE" == noti_type) {
+    long number;
+    PlatformResult status = GetNumber(noti_handle, NOTIFICATION_TEXT_TYPE_EVENT_COUNT, &number);
+    if (status.IsError()) {
+      LoggerE("Failed: GetNumber");
+      return status;
+    }
+    if (number > 0)
+      noti_layout = NOTIFICATION_LY_NOTI_EVENT_MULTIPLE;
+    else
+      noti_layout = NOTIFICATION_LY_NOTI_EVENT_SINGLE;
+  } else if ("THUMBNAIL" == noti_type) {
+    noti_layout = NOTIFICATION_LY_NOTI_THUMBNAIL;
+  }
+  if ("ONGOING" == noti_type) {
+    noti_layout = NOTIFICATION_LY_ONGOING_EVENT;
+  } else if ("PROGRESS" == noti_type) {
+    noti_layout = NOTIFICATION_LY_ONGOING_PROGRESS;
+  }
+  int ret = notification_set_layout(noti_handle, noti_layout);
+  if (NOTIFICATION_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification layout error",
+                              ("Set notification layout error: %d", ret));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+static bool ServiceExtraDataCb(app_control_h service, const char* key, void* user_data) {
+  ScopeLogger();
+  if (nullptr == user_data || nullptr == key) {
+    LoggerE("User data or key not exist");
+    return true;
+  }
+
+  picojson::array* control_data = static_cast<picojson::array*>(user_data);
+
+  int length = 0;
+  char** value = nullptr;
+  SCOPE_EXIT {
+    free(value);
+  };
+
+  int ret = app_control_get_extra_data_array(service, key, &value, &length);
+  if (APP_CONTROL_ERROR_NONE != ret) {
+    LoggerE("Get app control extra data error: %d", ret);
+    return true;
+  }
+
+  if (!value || !length) {
+    LoggerE("Get app control extra data value error");
+    return true;
+  }
+
+  picojson::array values = picojson::array();
+  for (int index = 0; index < length; ++index) {
+    values.push_back(picojson::value(value[index]));
+  }
+
+  picojson::object data_control_elem = picojson::object();
+  data_control_elem["key"] = picojson::value(key);
+  data_control_elem["value"] = picojson::value(values);
+
+  control_data->push_back(picojson::value(data_control_elem));
+
+  return true;
+}
+
+PlatformResult CommonNotification::Create(notification_type_e noti_type,
+                                          notification_h* noti_handle) {
+  ScopeLogger();
+  *noti_handle = notification_create(noti_type);
+  if (!*noti_handle) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Cannot make new notification object");
+  }
+
+  if (NOTIFICATION_TYPE_ONGOING == noti_type) {
+    int ret =
+        notification_set_display_applist(*noti_handle, NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY |
+                                                           NOTIFICATION_DISPLAY_APP_INDICATOR);
+    if (NOTIFICATION_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Cannot set notification display applist",
+                                ("Cannot make new notification object: %d", ret));
+    }
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::StatusTypeFromPlatform(notification_type_e noti_type,
+                                                          notification_ly_type_e noti_layout,
+                                                          std::string* type) {
+  ScopeLogger();
+  if (NOTIFICATION_TYPE_NOTI == noti_type) {
+    if (NOTIFICATION_LY_NOTI_EVENT_SINGLE == noti_layout ||
+        NOTIFICATION_LY_NOTI_EVENT_MULTIPLE == noti_layout) {
+      *type = "SIMPLE";
+    } else if (NOTIFICATION_LY_NOTI_THUMBNAIL == noti_layout) {
+      *type = "THUMBNAIL";
+    }
+  } else if (NOTIFICATION_TYPE_ONGOING == noti_type) {
+    if (NOTIFICATION_LY_ONGOING_EVENT == noti_layout) {
+      *type = "ONGOING";
+    } else if (NOTIFICATION_LY_ONGOING_PROGRESS == noti_layout) {
+      *type = "PROGRESS";
+    }
+  } else {
+    return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Notification type not found");
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::StatusTypeToPlatform(const std::string& type,
+                                                        notification_type_e* noti_type) {
+  ScopeLogger();
+  if ("SIMPLE" == type || "THUMBNAIL" == type) {
+    *noti_type = NOTIFICATION_TYPE_NOTI;
+  } else if ("ONGOING" == type || "PROGRESS" == type) {
+    *noti_type = NOTIFICATION_TYPE_ONGOING;
+  } else {
+    return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "Invalide notification type",
+                              ("Invalide noti type: %s", type.c_str()));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetImage(notification_h noti_handle,
+                                            notification_image_type_e image_type,
+                                            std::string* image_path) {
+  ScopeLogger();
+  char* path = nullptr;
+
+  *image_path = "";
+
+  if (NOTIFICATION_ERROR_NONE != notification_get_image(noti_handle, image_type, &path)) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification image error",
+                              ("Get notification image error, image_type: %d", image_type));
+  }
+  if (path) {
+    *image_path = path;
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetImage(notification_h noti_handle,
+                                            notification_image_type_e image_type,
+                                            const std::string& image_path) {
+  ScopeLogger();
+  int ret = notification_set_image(noti_handle, image_type, image_path.c_str());
+  if (NOTIFICATION_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "Set notification image error",
+        ("Set notification image error, image_type: %d, error: %d", image_type, ret));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetText(notification_h noti_handle,
+                                           notification_text_type_e text_type,
+                                           std::string* noti_text) {
+  ScopeLogger();
+  char* text = nullptr;
+
+  *noti_text = "";
+
+  if (NOTIFICATION_ERROR_NONE != notification_get_text(noti_handle, text_type, &text)) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification text error",
+                              ("Get notification text error, text_type: %d", text_type));
+  }
+
+  if (text) *noti_text = text;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetText(notification_h noti_handle,
+                                           notification_text_type_e text_type,
+                                           const std::string& noti_text) {
+  ScopeLogger();
+  int ret = notification_set_text(noti_handle, text_type, noti_text.c_str(), nullptr,
+                                  NOTIFICATION_VARIABLE_TYPE_NONE);
+  if (NOTIFICATION_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "Set notification text error",
+        ("Set notification text error, text_type: %d, error: %d", text_type, ret));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetNumber(notification_h noti_handle,
+                                             notification_text_type_e text_type, long* number) {
+  ScopeLogger();
+  std::string text;
+  PlatformResult status = GetText(noti_handle, text_type, &text);
+  CHECK_ERROR(status);
+
+  if (text.length())
+    *number = std::stol(text);
+  else
+    *number = -1;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetLedColor(notification_h noti_handle, std::string* led_color) {
+  ScopeLogger();
+  unsigned int color = 0;
+  notification_led_op_e type = NOTIFICATION_LED_OP_ON;
+
+  if (NOTIFICATION_ERROR_NONE != notification_get_led(noti_handle, &type, (int*)&color)) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
+                              "Get notification led displaying option error");
+  }
+
+  *led_color = "";
+  std::stringstream stream;
+
+  if (NOTIFICATION_LED_OP_OFF != type) {
+    color = 0x00FFFFFF & color;
+    stream << std::hex << color;
+    *led_color = "#" + stream.str();
+
+    while (led_color->length() < 7) {
+      led_color->insert(1, "0");
+    }
+
+    std::transform(led_color->begin(), led_color->end(), led_color->begin(), ::tolower);
+  }
+
+  LoggerD("color:%s", (*led_color).c_str());
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetLedPeriod(notification_h noti_handle,
+                                                unsigned long* on_period,
+                                                unsigned long* off_period) {
+  ScopeLogger();
+  int on_time = 0;
+  int off_time = 0;
+
+  if (NOTIFICATION_ERROR_NONE !=
+      notification_get_led_time_period(noti_handle, &on_time, &off_time)) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification led on/off period error");
+  }
+
+  if (on_period) *on_period = on_time;
+  if (off_period) *off_period = off_time;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetSoundPath(notification_h noti_handle,
+                                                std::string* sound_path) {
+  ScopeLogger();
+  *sound_path = "";
+
+  const char* path = nullptr;
+  notification_sound_type_e type = NOTIFICATION_SOUND_TYPE_NONE;
+
+  if (NOTIFICATION_ERROR_NONE != notification_get_sound(noti_handle, &type, &path)) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification sound error");
+  }
+
+  LoggerD("Sound type = %d", type);
+
+  if (path && (NOTIFICATION_SOUND_TYPE_USER_DATA == type)) {
+    *sound_path = path;
+  }
+
+  LoggerD("Sound path = %s", sound_path->c_str());
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetSoundPath(notification_h noti_handle,
+                                                const std::string& sound_path) {
+  ScopeLogger();
+  int ret =
+      notification_set_sound(noti_handle, NOTIFICATION_SOUND_TYPE_USER_DATA, sound_path.c_str());
+  if (NOTIFICATION_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification sound error",
+                              ("Set notification sound error: %d", ret));
+  }
+
+  LoggerD("Sound path = %s", sound_path.c_str());
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetVibration(notification_h noti_handle, bool* vibration) {
+  ScopeLogger();
+  notification_vibration_type_e vib_type = NOTIFICATION_VIBRATION_TYPE_NONE;
+
+  if (NOTIFICATION_ERROR_NONE != notification_get_vibration(noti_handle, &vib_type, nullptr)) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification vibration error");
+  }
+
+  if (NOTIFICATION_VIBRATION_TYPE_DEFAULT == vib_type ||
+      NOTIFICATION_VIBRATION_TYPE_USER_DATA == vib_type) {
+    *vibration = true;
+  } else {
+    *vibration = false;
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetApplicationControl(app_control_h app_handle,
+                                                         picojson::object* out_ptr) {
+  ScopeLogger();
+  picojson::object& out = *out_ptr;
+
+  char* operation = nullptr;
+  char* uri = nullptr;
+  char* mime = nullptr;
+  char* category = nullptr;
+  SCOPE_EXIT {
+    free(operation);
+    free(uri);
+    free(mime);
+    free(category);
+  };
+
+  int ret = app_control_get_operation(app_handle, &operation);
+  if (APP_CONTROL_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get application control operation error",
+                              ("Get application control operation error: %d", ret));
+  }
+  if (operation) {
+    out["operation"] = picojson::value(operation);
+    LoggerD("operation = %s", operation);
+  }
+
+  if (APP_CONTROL_ERROR_NONE != app_control_get_uri(app_handle, &uri)) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get application control uri error");
+  }
+  if (uri) {
+    out["uri"] = picojson::value(uri);
+    LoggerD("uri = %s", uri);
+  }
+
+  if (APP_CONTROL_ERROR_NONE != app_control_get_mime(app_handle, &mime)) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get application control mime error");
+  }
+  if (mime) {
+    out["mime"] = picojson::value(mime);
+    LoggerD("mime = %s", mime);
+  }
+
+  if (APP_CONTROL_ERROR_NONE != app_control_get_category(app_handle, &category)) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get application control category error");
+  }
+  if (category) {
+    out["category"] = picojson::value(category);
+    LoggerD("category = %s", category);
+  }
+
+  picojson::array app_control_data = picojson::array();
+  if (APP_CONTROL_ERROR_NONE !=
+      app_control_foreach_extra_data(app_handle, ServiceExtraDataCb, (void*)&app_control_data)) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get application control data error");
+  }
+  out["data"] = picojson::value(app_control_data);
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetApplicationControl(app_control_h app_handle,
+                                                         const picojson::object& app_ctrl) {
+  ScopeLogger();
+  picojson::value val(app_ctrl);
+  const std::string& operation = FromJson<std::string>(app_ctrl, "operation");
+
+  int ret;
+  if (operation.length()) {
+    ret = app_control_set_operation(app_handle, operation.c_str());
+  } else {
+    ret = app_control_set_operation(app_handle, APP_CONTROL_OPERATION_DEFAULT);
+  }
+  if (APP_CONTROL_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set application control operation error",
+                              ("Set application control operation error: %d", ret));
+  }
+
+  if (val.contains("uri") && !IsNull(app_ctrl, "uri")) {
+    const std::string& uri = FromJson<std::string>(app_ctrl, "uri");
+    ret = app_control_set_uri(app_handle, uri.c_str());
+    if (APP_CONTROL_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set application control uri error",
+                                ("Set application control uri error: %d", ret));
+    }
+  }
+
+  if (val.contains("mime") && !IsNull(app_ctrl, "mime")) {
+    const std::string& mime = FromJson<std::string>(app_ctrl, "mime");
+    ret = app_control_set_mime(app_handle, mime.c_str());
+    if (APP_CONTROL_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set application control mime error",
+                                ("Set application control mime error: %d", ret));
+    }
+  }
+
+  if (val.contains("category") && !IsNull(app_ctrl, "category")) {
+    const std::string& category = FromJson<std::string>(app_ctrl, "category");
+    ret = app_control_set_category(app_handle, category.c_str());
+    if (APP_CONTROL_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set application control category error",
+                                ("Set application control category error: %d", ret));
+    }
+  }
+
+  if (!picojson::value(app_ctrl).contains("data") || IsNull(app_ctrl, "data")) {
+    return PlatformResult(ErrorCode::NO_ERROR);
+  }
+
+  auto& items = FromJson<picojson::array>(app_ctrl, "data");
+
+  int idx = 0;
+
+  for (auto item : items) {
+    const picojson::object& obj = JsonCast<picojson::object>(item);
+    const std::string key = FromJson<std::string>(obj, "key");
+    const picojson::array values = FromJson<picojson::array>(obj, "value");
+    const char** arrayValue = (const char**)calloc(sizeof(char*), values.size());
+    SCOPE_EXIT {
+      free(arrayValue);
+    };
+    idx = 0;
+    for (auto& item : values) {
+      arrayValue[idx] = JsonCast<std::string>(item).c_str();
+      ++idx;
+    }
+    ret = app_control_add_extra_data_array(app_handle, key.c_str(), arrayValue, values.size());
+    if (APP_CONTROL_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set application control extra data error",
+                                ("Set application control extra data error: %d", ret));
+    }
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetApplicationId(app_control_h app_handle, std::string* app_id) {
+  ScopeLogger();
+  char* app_id_str = nullptr;
+  SCOPE_EXIT {
+    free(app_id_str);
+  };
+
+  *app_id = "";
+
+  if (APP_CONTROL_ERROR_NONE != app_control_get_app_id(app_handle, &app_id_str)) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get applicaiton ID failed");
+  }
+
+  if (nullptr != app_id_str) {
+    *app_id = app_id_str;
+  }
+
+  LoggerD("Get appId = %s", /*(*app_id).c_str()*/ app_id_str);
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetApplicationId(app_control_h app_handle,
+                                                    const std::string& app_id) {
+  ScopeLogger();
+  int ret = app_control_set_app_id(app_handle, app_id.c_str());
+  if (APP_CONTROL_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set applicaiton ID error",
+                              ("Set applicaiton ID error: %d", ret));
+  }
+
+  LoggerD("Set appId = %s", app_id.c_str());
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetProgressValue(notification_h noti_handle,
+                                                    const std::string& progress_type,
+                                                    double* progress_value) {
+  ScopeLogger();
+  double tmp_progress_value = 0.0;
+
+  if (kProgressTypeByte == progress_type) {
+    if (NOTIFICATION_ERROR_NONE != notification_get_size(noti_handle, &tmp_progress_value)) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification size error");
+    }
+  } else if (kProgressTypePercentage == progress_type) {
+    if (NOTIFICATION_ERROR_NONE != notification_get_progress(noti_handle, &tmp_progress_value)) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification progress error");
+    }
+    // native api uses range 0-1, but webapi expects 0-100, so we need to multiply result with 100
+    tmp_progress_value *= 100;
+  } else {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown notification progress type",
+                              ("Unknown notification progress type: %s ", progress_type.c_str()));
+  }
+
+  LoggerD("Progress %s = %lf", progress_type.c_str(), tmp_progress_value);
+
+  *progress_value = tmp_progress_value;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetProgressValue(notification_h noti_handle,
+                                                    const std::string& progress_type,
+                                                    double progress_value, bool is_update) {
+  ScopeLogger();
+  int ret;
+
+  if (kProgressTypeByte == progress_type) {
+    ret = notification_set_size(noti_handle, progress_value);
+
+    if (is_update) {
+      ret = notification_update_size(noti_handle, NOTIFICATION_PRIV_ID_NONE, progress_value);
+    }
+  } else if (kProgressTypePercentage == progress_type) {
+    // native api uses range 0-1, but webapi expects 0-100, so we need to divide by 100
+    ret = notification_set_progress(noti_handle, progress_value / 100);
+
+    if (is_update) {
+      ret = notification_update_progress(noti_handle, NOTIFICATION_PRIV_ID_NONE, progress_value);
+    }
+  } else {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown notification progress type",
+                              ("Unknown notification progress type: %s ", progress_type.c_str()));
+  }
+
+  if (NOTIFICATION_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification progress/size error",
+                              ("Set notification progress/size error: %d", ret));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetPostedTime(notification_h noti_handle, time_t* posted_time) {
+  ScopeLogger();
+  *posted_time = 0;
+
+  if (NOTIFICATION_ERROR_NONE != notification_get_insert_time(noti_handle, posted_time)) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification posted time error");
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetNotiHandle(int id, notification_h* noti_handle) {
+  ScopeLogger();
+  *noti_handle = notification_load(nullptr, id);
+  if (nullptr == *noti_handle) {
+    return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Not found or removed notification id");
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::GetAppControl(notification_h noti_handle,
+                                                 app_control_h* app_control) {
+  ScopeLogger();
+  int ret = notification_get_launch_option(noti_handle, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL,
+                                           static_cast<void*>(app_control));
+  if (NOTIFICATION_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Notification get launch option error",
+                              ("Notification get launch option error: %d", ret));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::CreateAppControl(app_control_h* app_control) {
+  ScopeLogger();
+  int ret = app_control_create(app_control);
+  if (APP_CONTROL_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Application create error",
+                              ("Application create error: %d", ret));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetAppControl(notification_h noti_handle,
+                                                 app_control_h app_control) {
+  ScopeLogger();
+  int ret = notification_set_launch_option(noti_handle, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL,
+                                           static_cast<void*>(app_control));
+  if (APP_CONTROL_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Notification set launch option error",
+                              ("Notification set launch option error: %d", ret));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::UpdateNotificationAfterPost(notification_h noti_handle, int id,
+                                                               picojson::object* out_ptr) {
+  time_t posted_time;
+  PlatformResult status = GetPostedTime(noti_handle, &posted_time);
+  CHECK_ERROR(status);
+
+  picojson::object& out = *out_ptr;
+  out["postedTime"] = picojson::value(static_cast<double>(posted_time) * 1000.0);
+  out["id"] = picojson::value(std::to_string(id));
+  out["type"] = picojson::value("STATUS");
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::PostNotification(const picojson::object& args, bool is_update,
+                                                    picojson::object* out_ptr,
+                                                    GetHandleFromJsonFun getHandle) {
+  ScopeLogger();
+  notification_h noti_handle = nullptr;
+  int ret = NOTIFICATION_ERROR_NONE;
+  int id = NOTIFICATION_PRIV_ID_NONE;
+
+  SCOPE_EXIT {
+    notification_free(noti_handle);
+  };
+
+  const auto& noti_val_it = args.find("notification");
+  if (args.end() == noti_val_it) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Cannot post notification");
+  }
+  PlatformResult status = getHandle(noti_val_it->second, is_update, &noti_handle);
+  CHECK_ERROR(status);
+
+  if (is_update) {
+    ret = notification_update(noti_handle);
+    if (NOTIFICATION_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Update notification error",
+                                ("Update notification error: %d", ret));
+    }
+    return PlatformResult(ErrorCode::NO_ERROR);
+  } else {
+    ret = notification_insert(noti_handle, &id);
+    if (NOTIFICATION_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Cannot insert notification",
+                                ("Cannot insert notification: %d", ret));
+    }
+  }
+
+  return UpdateNotificationAfterPost(noti_handle, id, out_ptr);
+}
+
+PlatformResult CommonNotification::AddCommonMembersToJson(int id, notification_h noti_handle,
+                                                          picojson::object* out_ptr) {
+  ScopeLogger();
+  picojson::object& out = *out_ptr;
+
+  out["id"] = picojson::value(std::to_string(id));
+  out["type"] = picojson::value("STATUS");
+
+  time_t posted_time = 0;
+  PlatformResult ret = GetPostedTime(noti_handle, &posted_time);
+  CHECK_ERROR(ret);
+  out["postedTime"] = picojson::value(static_cast<double>(posted_time) * 1000.0);
+
+  std::string value_str;
+  ret = GetText(noti_handle, NOTIFICATION_TEXT_TYPE_TITLE, &value_str);
+  CHECK_ERROR(ret);
+  out["title"] = picojson::value(value_str);
+
+  ret = GetText(noti_handle, NOTIFICATION_TEXT_TYPE_CONTENT, &value_str);
+  CHECK_ERROR(ret);
+  if (value_str.length()) {
+    out["content"] = picojson::value(value_str);
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddTypeToJson(notification_h noti_handle, const std::string& key,
+                                                 picojson::object* out_ptr,
+                                                 std::string* noti_type_str) {
+  ScopeLogger();
+  picojson::object& out = *out_ptr;
+  // Notification type
+  notification_type_e noti_type = NOTIFICATION_TYPE_NONE;
+  int ret = notification_get_type(noti_handle, &noti_type);
+  if (NOTIFICATION_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Notification get type error",
+                              ("Notification get type error: %d", ret));
+  }
+
+  notification_ly_type_e noti_layout = NOTIFICATION_LY_NONE;
+  ret = notification_get_layout(noti_handle, &noti_layout);
+  if (NOTIFICATION_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Notification get layout error",
+                              ("Notification get layout error: %d", ret));
+  }
+
+  PlatformResult status = StatusTypeFromPlatform(noti_type, noti_layout, noti_type_str);
+  CHECK_ERROR(status);
+  out[key] = picojson::value(*noti_type_str);
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddProgressTypeAndValueToJson(notification_h noti_handle,
+                                                                 const std::string& noti_type_str,
+                                                                 picojson::object* out_ptr) {
+  ScopeLogger();
+
+  picojson::object& out = *out_ptr;
+  std::string progress_type;
+  // native code does not support progress_type value, we are using NOTIFICATION_IMAGE_TYPE_LIST_5
+  // to store this field on native level
+  PlatformResult status = GetImage(noti_handle, NOTIFICATION_IMAGE_TYPE_LIST_5, &progress_type);
+  CHECK_ERROR(status)
+
+  // notification service daemon doesn't set progress type - NOTIFICATION_IMAGE_TYPE_LIST_5 is used
+  // as workaround, so use default if notification type is different from "PROGRESS"
+  if ("PROGRESS" != noti_type_str) {
+    progress_type = progress_type == kProgressTypeByte ? progress_type : kProgressTypePercentage;
+  }
+  out["progressType"] = picojson::value(progress_type);
+
+  double progress_value;
+  status = GetProgressValue(noti_handle, progress_type, &progress_value);
+  CHECK_ERROR(status);
+  out["progressValue"] = picojson::value(progress_value);
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddEventsNumberToJson(notification_h noti_handle,
+                                                         const std::string& key,
+                                                         picojson::object* out_ptr) {
+  ScopeLogger();
+  picojson::object& out = *out_ptr;
+
+  long number = 0;
+  PlatformResult status = GetNumber(noti_handle, NOTIFICATION_TEXT_TYPE_EVENT_COUNT, &number);
+  CHECK_ERROR(status);
+  if (number >= 0) {
+    out[key] = picojson::value(static_cast<double>(number));
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddDetailInfosToJson(notification_h noti_handle,
+                                                        picojson::object* out_ptr) {
+  ScopeLogger();
+  picojson::object& out = *out_ptr;
+
+  picojson::value result_json = picojson::value(picojson::array());
+  picojson::array& detail_info_array = result_json.get<picojson::array>();
+
+  if (info_map_.size() != info_sub_map_.size()) {
+    return LogAndCreateResult(ErrorCode::VALIDATION_ERR,
+                              "Different notification information types element size");
+  }
+
+  picojson::value detail_info = picojson::value(picojson::object());
+  picojson::object& detail_info_obj = detail_info.get<picojson::object>();
+
+  std::string text;
+  size_t info_map_size = info_map_.size();
+  for (size_t idx = 0; idx < info_map_size; ++idx) {
+    PlatformResult status = GetText(noti_handle, info_map_.at(idx), &text);
+    CHECK_ERROR(status);
+
+    if (text.length()) {
+      detail_info_obj["mainText"] = picojson::value(text);
+
+      status = AddTextToJson(noti_handle, info_sub_map_.at(idx), "subText", &detail_info_obj);
+      CHECK_ERROR(status);
+      detail_info_array.push_back(detail_info);
+    }
+  }
+  out["detailInfo"] = result_json;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddPathToJson(notification_h noti_handle,
+                                                 notification_image_type_e type,
+                                                 const std::string& key,
+                                                 picojson::object* out_ptr) {
+  picojson::object& out = *out_ptr;
+
+  std::string value_str;
+  PlatformResult status = GetImage(noti_handle, type, &value_str);
+  CHECK_ERROR(status);
+  if (value_str.length()) {
+    out[key] = picojson::value(FilesystemProvider::Create().GetVirtualPath(value_str));
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddTextToJson(notification_h noti_handle,
+                                                 notification_text_type_e type,
+                                                 const std::string& key,
+                                                 picojson::object* out_ptr) {
+  picojson::object& out = *out_ptr;
+
+  std::string value_str;
+  PlatformResult ret = GetText(noti_handle, type, &value_str);
+  CHECK_ERROR(ret);
+  if (value_str.length()) {
+    out[key] = picojson::value(value_str);
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddLedOnOffPeriodToJson(notification_h noti_handle,
+                                                           picojson::object* out_ptr) {
+  ScopeLogger();
+  picojson::object& out = *out_ptr;
+
+  unsigned long on_period = 0;
+  unsigned long off_period = 0;
+  PlatformResult status = GetLedPeriod(noti_handle, &on_period, &off_period);
+  CHECK_ERROR(status);
+
+  out["ledOnPeriod"] = picojson::value(static_cast<double>(on_period));
+  out["ledOffPeriod"] = picojson::value(static_cast<double>(off_period));
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddPathsArrayToJson(notification_h noti_handle, ImageEnumMap map,
+                                                       const std::string& key,
+                                                       picojson::object* out_ptr) {
+  ScopeLogger();
+  picojson::object& out = *out_ptr;
+
+  picojson::value result_json = picojson::value(picojson::array());
+  picojson::array& result_array = result_json.get<picojson::array>();
+
+  std::string path;
+  size_t map_size = map.size();
+  for (size_t idx = 0; idx < map_size; ++idx) {
+    PlatformResult status = GetImage(noti_handle, map.at(idx), &path);
+    CHECK_ERROR(status);
+
+    if (path.length()) {
+      result_array.push_back(picojson::value(FilesystemProvider::Create().GetVirtualPath(path)));
+    }
+  }
+
+  out[key] = result_json;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddTextsArrayToJson(notification_h noti_handle,
+                                                       InformationEnumMap map,
+                                                       const std::string& key,
+                                                       picojson::object* out_ptr) {
+  ScopeLogger();
+  picojson::object& out = *out_ptr;
+
+  picojson::value result_json = picojson::value(picojson::array());
+  picojson::array& result_array = result_json.get<picojson::array>();
+
+  std::string text;
+  size_t map_size = map.size();
+  for (size_t idx = 0; idx < map_size; ++idx) {
+    PlatformResult status = GetText(noti_handle, map.at(idx), &text);
+
+    CHECK_ERROR(status);
+    if (text.length()) {
+      result_array.push_back(picojson::value(text));
+    }
+  }
+
+  out[key] = result_json;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddLedColorToJson(notification_h noti_handle,
+                                                     picojson::object* out_ptr) {
+  ScopeLogger();
+  picojson::object& out = *out_ptr;
+
+  std::string color;
+  PlatformResult status = GetLedColor(noti_handle, &color);
+  CHECK_ERROR(status);
+  if (color.length()) {
+    out["ledColor"] = picojson::value(color);
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddSoundPathToJson(notification_h noti_handle,
+                                                      picojson::object* out_ptr) {
+  ScopeLogger();
+  picojson::object& out = *out_ptr;
+
+  std::string sound_path;
+  PlatformResult status = GetSoundPath(noti_handle, &sound_path);
+  CHECK_ERROR(status);
+  if (sound_path.length()) {
+    out["soundPath"] = picojson::value(FilesystemProvider::Create().GetVirtualPath(sound_path));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddVibrationToJson(notification_h noti_handle,
+                                                      picojson::object* out_ptr) {
+  ScopeLogger();
+  picojson::object& out = *out_ptr;
+
+  bool vibration;
+  PlatformResult status = GetVibration(noti_handle, &vibration);
+  CHECK_ERROR(status);
+  out["vibration"] = picojson::value(vibration);
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::AddAppControlInfoToJson(notification_h noti_handle,
+                                                           app_control_h app_handle,
+                                                           picojson::object* out_ptr) {
+  ScopeLogger();
+  picojson::object& out = *out_ptr;
+
+  if (app_handle) {
+    picojson::object app_control = picojson::object();
+    PlatformResult status = GetApplicationControl(app_handle, &app_control);
+    CHECK_ERROR(status);
+    if (app_control.size()) {
+      out["appControl"] = picojson::value(app_control);
+    }
+
+    std::string app_id;
+    status = GetApplicationId(app_handle, &app_id);
+    CHECK_ERROR(status);
+    if (app_id.length()) {
+      out["appId"] = picojson::value(app_id);
+    }
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::InitNotiFromJson(const picojson::object& noti_obj,
+                                                    const std::string& type_key, bool is_update,
+                                                    notification_h* noti_handle) {
+  ScopeLogger();
+  notification_h tmp_noti = nullptr;
+
+  const std::string& status_type = FromJson<std::string>(noti_obj, type_key.c_str());
+
+  notification_type_e noti_type = NOTIFICATION_TYPE_NONE;
+  PlatformResult status = StatusTypeToPlatform(status_type, &noti_type);
+  CHECK_ERROR(status);
+
+  if (is_update) {
+    int id = std::stoi(FromJson<std::string>(noti_obj, "id"));
+
+    status = GetNotiHandle(id, &tmp_noti);
+    CHECK_ERROR(status);
+  } else {
+    status = Create(noti_type, &tmp_noti);
+    CHECK_ERROR(status);
+  }
+  std::unique_ptr<std::remove_pointer<notification_h>::type, int (*)(notification_h)> tmp_noti_ptr(
+      tmp_noti, &notification_free);  // automatically release the memory
+
+  status = SetLayout(tmp_noti, status_type);
+  CHECK_ERROR(status);
+
+  *noti_handle = tmp_noti_ptr.release();
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetCommonMembersFromJson(const picojson::value& noti_value,
+                                                            notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+  PlatformResult status =
+      SetText(noti_handle, NOTIFICATION_TEXT_TYPE_TITLE, FromJson<std::string>(noti_obj, "title"));
+  CHECK_ERROR(status);
+
+  SetTextFromJson(noti_value, NOTIFICATION_TEXT_TYPE_CONTENT, "content", noti_handle);
+  CHECK_ERROR(status);
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetPathFromJson(const picojson::value& noti_value,
+                                                   notification_image_type_e type,
+                                                   const std::string& key,
+                                                   notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+  if (noti_value.contains(key) && !IsNull(noti_obj, key.c_str())) {
+    const std::string& value_str = FromJson<std::string>(noti_obj, key.c_str());
+    std::string real_path = FilesystemProvider::Create().GetRealPath(value_str);
+
+    PlatformResult status = SetImage(noti_handle, type, real_path);
+    CHECK_ERROR(status);
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetLedColorFromJson(const picojson::value& noti_value,
+                                                       notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+  if (noti_value.contains("ledColor") && !IsNull(noti_obj, "ledColor")) {
+    std::string color_str = FromJson<std::string>(noti_obj, "ledColor");
+    std::transform(color_str.begin(), color_str.end(), color_str.begin(), ::tolower);
+
+    if (!IsColorFormatNumeric(color_str)) {
+      return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Led color is not numeric value",
+                                ("Led color is not numeric value: %s", color_str.c_str()));
+    }
+
+    std::stringstream stream;
+    unsigned int color = 0;
+    notification_led_op_e type = NOTIFICATION_LED_OP_ON;
+    std::string color_code = color_str.substr(1, color_str.length()).insert(0, "ff");
+
+    stream << std::hex << color_code;
+    stream >> color;
+
+    if (0 != color)
+      type = NOTIFICATION_LED_OP_ON_CUSTOM_COLOR;
+    else
+      type = NOTIFICATION_LED_OP_OFF;
+
+    int ret = notification_set_led(noti_handle, type, static_cast<int>(color));
+    if (NOTIFICATION_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification led color eror",
+                                ("Set notification led color eror: %d", ret));
+    }
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetLedOnPeriodFromJson(const picojson::value& noti_value,
+                                                          notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+  unsigned long on_period = static_cast<unsigned long>(FromJson<double>(noti_obj, "ledOnPeriod"));
+
+  unsigned long off_period = 0;
+  PlatformResult status = GetLedPeriod(noti_handle, nullptr, &off_period);
+  CHECK_ERROR(status);
+
+  int ret = notification_set_led_time_period(noti_handle, on_period, off_period);
+  if (NOTIFICATION_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification led on period error",
+                              ("Set notification led on period error: %d", ret));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetLedOffPeriodFromJson(const picojson::value& noti_value,
+                                                           notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+  unsigned long off_period = static_cast<unsigned long>(FromJson<double>(noti_obj, "ledOffPeriod"));
+  unsigned long on_period = 0;
+  PlatformResult status = GetLedPeriod(noti_handle, &on_period, nullptr);
+  CHECK_ERROR(status);
+
+  int ret = notification_set_led_time_period(noti_handle, on_period, off_period);
+  if (NOTIFICATION_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification led off period error",
+                              ("Set notification led off period error: %d", ret));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetProgressTypeAndValueFromJson(
+    const picojson::value& noti_value, bool is_update, notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+
+  // progressType
+  // native code does not support progress_type value, we are using NOTIFICATION_IMAGE_TYPE_LIST_5
+  // to store this field on native level
+  const std::string& progress_type = FromJson<std::string>(noti_obj, "progressType");
+  PlatformResult status = SetImage(noti_handle, NOTIFICATION_IMAGE_TYPE_LIST_5, progress_type);
+  CHECK_ERROR(status);
+
+  // progressValue
+  double progress_value = -1;
+  if (noti_value.contains("progressValue") && !IsNull(noti_obj, "progressValue")) {
+    progress_value = FromJson<double>(noti_obj, "progressValue");
+  }
+  status = SetProgressValue(noti_handle, progress_type, progress_value, is_update);
+  CHECK_ERROR(status);
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetAppControlInfoFromJson(const picojson::value& noti_value,
+                                                             notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+
+  app_control_h app_control = nullptr;
+  SCOPE_EXIT {
+    if (app_control) {
+      app_control_destroy(app_control);
+    }
+  };
+
+  PlatformResult status = CreateAppControl(&app_control);
+  CHECK_ERROR(status);
+
+  if (noti_value.contains("appControl") && !IsNull(noti_obj, "appControl")) {
+    status = SetApplicationControl(app_control, FromJson<picojson::object>(noti_obj, "appControl"));
+    CHECK_ERROR(status);
+  }
+
+  if (noti_value.contains("appId") && !IsNull(noti_obj, "appId")) {
+    status = SetApplicationId(app_control, FromJson<std::string>(noti_obj, "appId"));
+    CHECK_ERROR(status);
+  }
+
+  status = SetAppControl(noti_handle, app_control);
+  CHECK_ERROR(status);
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetEventsNumberFromJson(const picojson::value& noti_value,
+                                                           const std::string& key,
+                                                           notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+
+  if (noti_value.contains(key) && !IsNull(noti_obj, key.c_str())) {
+    long number = (long)FromJson<double>(noti_obj, key.c_str());
+    PlatformResult status =
+        SetText(noti_handle, NOTIFICATION_TEXT_TYPE_EVENT_COUNT, std::to_string(number));
+    CHECK_ERROR(status);
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetDetailInfosFromJson(const picojson::value& noti_value,
+                                                          notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+  if (noti_value.contains("detailInfo") && !IsNull(noti_obj, "detailInfo")) {
+    const picojson::array& array = FromJson<picojson::array>(noti_obj, "detailInfo");
+
+    if (array.size() > info_map_.size()) {
+      return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR,
+                                "Too many values in notification detailInfo array");
+    }
+    size_t idx = 0;
+
+    for (auto& item : array) {
+      const picojson::object& obj = JsonCast<picojson::object>(item);
+
+      PlatformResult status =
+          SetText(noti_handle, info_map_.at(idx), FromJson<std::string>(obj, "mainText"));
+      CHECK_ERROR(status);
+
+      SetTextFromJson(picojson::value(obj), info_sub_map_.at(idx), "subText", noti_handle);
+      CHECK_ERROR(status);
+      ++idx;
+    }
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetVibrationFromJson(const picojson::value& noti_value,
+                                                        notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+  bool vibration = FromJson<bool>(noti_obj, "vibration");
+
+  bool platform_vibration;
+  PlatformResult status = GetVibration(noti_handle, &platform_vibration);
+  CHECK_ERROR(status);
+
+  if (platform_vibration != vibration) {
+    notification_vibration_type_e vib_type = NOTIFICATION_VIBRATION_TYPE_NONE;
+
+    if (vibration) {
+      vib_type = NOTIFICATION_VIBRATION_TYPE_DEFAULT;
+    }
+
+    int ret = notification_set_vibration(noti_handle, vib_type, nullptr);
+    if (NOTIFICATION_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification vibration error",
+                                ("Set notification vibration error: %d", ret));
+    }
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetSoundPathFromJson(const picojson::value& noti_value,
+                                                        notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+
+  if (noti_value.contains("soundPath") && !IsNull(noti_obj, "soundPath")) {
+    const std::string& value_str = FromJson<std::string>(noti_obj, "soundPath");
+    std::string real_path = FilesystemProvider::Create().GetRealPath(value_str);
+
+    PlatformResult status = SetSoundPath(noti_handle, real_path);
+    CHECK_ERROR(status);
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetPathsArrayFromJson(const picojson::value& noti_value,
+                                                         ImageEnumMap map, const std::string& key,
+                                                         notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+
+  if (noti_value.contains(key) && !IsNull(noti_obj, key.c_str())) {
+    const picojson::array& array = FromJson<picojson::array>(noti_obj, key.c_str());
+    if (array.size() > map.size()) {
+      return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Too many values in array");
+    }
+    size_t idx = 0;
+    for (auto& item : array) {
+      const std::string& text = JsonCast<std::string>(item);
+      std::string real_path = FilesystemProvider::Create().GetRealPath(text);
+
+      PlatformResult status = SetImage(noti_handle, map.at(idx), real_path);
+      CHECK_ERROR(status);
+
+      ++idx;
+    }
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetTextsArrayFromJson(const picojson::value& noti_value,
+                                                         InformationEnumMap map,
+                                                         const std::string& key,
+                                                         notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+
+  if (noti_value.contains(key) && !IsNull(noti_obj, key.c_str())) {
+    const picojson::array& array = FromJson<picojson::array>(noti_obj, key.c_str());
+    if (array.size() > map.size()) {
+      return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Too many values in array");
+    }
+
+    size_t idx = 0;
+    for (auto& item : array) {
+      const std::string& text = JsonCast<std::string>(item);
+      PlatformResult status = SetText(noti_handle, map.at(idx), text);
+      CHECK_ERROR(status);
+
+      ++idx;
+    }
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult CommonNotification::SetTextFromJson(const picojson::value& noti_value,
+                                                   notification_text_type_e type,
+                                                   const std::string& key,
+                                                   notification_h noti_handle) {
+  ScopeLogger();
+  const picojson::object& noti_obj = noti_value.get<picojson::object>();
+
+  if (noti_value.contains(key) && !IsNull(noti_obj, key.c_str())) {
+    PlatformResult status =
+        SetText(noti_handle, type, FromJson<std::string>(noti_obj, key.c_str()));
+    CHECK_ERROR(status);
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+}  // namespace notification
+}  // namespace extension
diff --git a/src/notification/common_notification.h b/src/notification/common_notification.h
new file mode 100644 (file)
index 0000000..7bb17c4
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2015-2017 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 NOTIFICATION_COMMON_NOTIFICATION_H_
+#define NOTIFICATION_COMMON_NOTIFICATION_H_
+
+#include <app_control.h>
+#include <notification.h>
+#include <functional>
+
+#include "common/picojson.h"
+#include "common/platform_result.h"
+
+#include "common/XW_Extension.h"
+
+namespace extension {
+namespace notification {
+
+#define CHECK_ERROR(ret) \
+  if (ret.IsError()) {   \
+    return ret;          \
+  }
+
+const std::string kProgressTypePercentage = "PERCENTAGE";
+const std::string kProgressTypeByte = "BYTE";
+
+typedef std::map<int, notification_text_type_e> InformationEnumMap;
+typedef std::map<int, notification_image_type_e> ImageEnumMap;
+
+typedef std::function<common::PlatformResult(const picojson::value& noti_val, bool is_update,
+                                             notification_h* noti_handle)>
+    GetHandleFromJsonFun;
+
+class CommonNotification {
+ public:
+  XW_EXPORT static common::PlatformResult GetAppControl(notification_h noti_handle,
+                                                        app_control_h* app_control);
+  static common::PlatformResult GetNotiHandle(int id, notification_h* noti_handle);
+  XW_EXPORT static common::PlatformResult SetAppControl(notification_h noti_handle,
+                                                        app_control_h app_control);
+
+  static const InformationEnumMap info_map_;
+  static const InformationEnumMap info_sub_map_;
+  static const ImageEnumMap thumbnails_map_;
+  static const InformationEnumMap buttons_texts_map_;
+  static const ImageEnumMap buttons_icon_paths_map_;
+
+  static common::PlatformResult StatusTypeFromPlatform(notification_type_e noti_type,
+                                                       notification_ly_type_e noti_layout,
+                                                       std::string* type);
+  static common::PlatformResult StatusTypeToPlatform(const std::string& type,
+                                                     notification_type_e* noti_type);
+  static common::PlatformResult Create(notification_type_e noti_type, notification_h* noti_handle);
+  static common::PlatformResult GetImage(notification_h noti_handle,
+                                         notification_image_type_e image_type,
+                                         std::string* image_path);
+  static common::PlatformResult SetImage(notification_h noti_handle,
+                                         notification_image_type_e image_type,
+                                         const std::string& image_path);
+  static common::PlatformResult GetText(notification_h noti_handle,
+                                        notification_text_type_e text_type, std::string* noti_text);
+  static common::PlatformResult SetText(notification_h noti_handle,
+                                        notification_text_type_e text_type,
+                                        const std::string& noti_text);
+  static common::PlatformResult GetNumber(notification_h noti_handle,
+                                          notification_text_type_e text_type, long* number);
+  static common::PlatformResult GetLedColor(notification_h noti_handle, std::string* led_color);
+  static common::PlatformResult GetLedPeriod(notification_h noti_handle, unsigned long* on_period,
+                                             unsigned long* off_period);
+  static common::PlatformResult GetSoundPath(notification_h noti_handle, std::string* sound_path);
+  static common::PlatformResult SetSoundPath(notification_h noti_handle,
+                                             const std::string& sound_path);
+  static common::PlatformResult GetVibration(notification_h noti_handle, bool* vibration);
+  static common::PlatformResult GetApplicationControl(app_control_h app_handle,
+                                                      picojson::object* out_ptr);
+  static common::PlatformResult SetApplicationControl(app_control_h app_handle,
+                                                      const picojson::object& app_ctrl);
+  static common::PlatformResult GetApplicationId(app_control_h app_handle, std::string* app_id);
+  static common::PlatformResult SetApplicationId(app_control_h app_handle,
+                                                 const std::string& app_id);
+  static common::PlatformResult GetProgressValue(notification_h noti_handle,
+                                                 const std::string& progess_type,
+                                                 double* progress_value);
+  static common::PlatformResult SetProgressValue(notification_h noti_handle,
+                                                 const std::string& progress_type,
+                                                 double progress_value, bool is_update);
+  static common::PlatformResult GetPostedTime(notification_h noti_handle, time_t* posted_time);
+  static common::PlatformResult SetLayout(notification_h noti_handle, const std::string& noti_type);
+  static common::PlatformResult CreateAppControl(app_control_h* app_control);
+
+  static bool IsColorFormatNumeric(const std::string& color);
+  static common::PlatformResult UpdateNotificationAfterPost(notification_h noti_handle, int id,
+                                                            picojson::object* out_ptr);
+
+  // ToJson section
+  static common::PlatformResult AddCommonMembersToJson(int id, notification_h noti_handle,
+                                                       picojson::object* out_ptr);
+  static common::PlatformResult AddTypeToJson(notification_h noti_handle, const std::string& key,
+                                              picojson::object* out_ptr,
+                                              std::string* noti_type_str);
+  static common::PlatformResult AddProgressTypeAndValueToJson(notification_h noti_handle,
+                                                              const std::string& noti_type_str,
+                                                              picojson::object* out_ptr);
+  static common::PlatformResult AddEventsNumberToJson(notification_h noti_handle,
+                                                      const std::string& key,
+                                                      picojson::object* out_ptr);
+  static common::PlatformResult AddDetailInfosToJson(notification_h noti_handle,
+                                                     picojson::object* out_ptr);
+  static common::PlatformResult AddPathToJson(notification_h noti_handle,
+                                              notification_image_type_e type,
+                                              const std::string& key, picojson::object* out_ptr);
+  static common::PlatformResult AddTextToJson(notification_h noti_handle,
+                                              notification_text_type_e type, const std::string& key,
+                                              picojson::object* out_ptr);
+  static common::PlatformResult AddIconPathToJson(notification_h noti_handle,
+                                                  picojson::object* out_ptr);
+  static common::PlatformResult AddSubIconPathToJson(notification_h noti_handle,
+                                                     picojson::object* out_ptr);
+  static common::PlatformResult AddBackgroundImagePathToJson(notification_h noti_handle,
+                                                             picojson::object* out_ptr);
+  static common::PlatformResult AddLedOnOffPeriodToJson(notification_h noti_handle,
+                                                        picojson::object* out_ptr);
+  static common::PlatformResult AddLedColorToJson(notification_h noti_handle,
+                                                  picojson::object* out_ptr);
+  static common::PlatformResult AddSoundPathToJson(notification_h noti_handle,
+                                                   picojson::object* out_ptr);
+  static common::PlatformResult AddVibrationToJson(notification_h noti_handle,
+                                                   picojson::object* out_ptr);
+  static common::PlatformResult AddAppControlInfoToJson(notification_h noti_handle,
+                                                        app_control_h app_handle,
+                                                        picojson::object* out_ptr);
+  static common::PlatformResult AddPathsArrayToJson(notification_h noti_handle, ImageEnumMap map,
+                                                    const std::string& key,
+                                                    picojson::object* out_ptr);
+  static common::PlatformResult AddTextsArrayToJson(notification_h noti_handle,
+                                                    InformationEnumMap map, const std::string& key,
+                                                    picojson::object* out_ptr);
+
+  // FromJson section
+  static common::PlatformResult InitNotiFromJson(const picojson::object& args,
+                                                 const std::string& type_key, bool is_update,
+                                                 notification_h* noti_handle);
+  static common::PlatformResult SetCommonMembersFromJson(const picojson::value& noti_val,
+                                                         notification_h noti_handle);
+  static common::PlatformResult SetPathFromJson(const picojson::value& noti_value,
+                                                notification_image_type_e type,
+                                                const std::string& key, notification_h noti_handle);
+  static common::PlatformResult SetLedColorFromJson(const picojson::value& noti_value,
+                                                    notification_h noti_handle);
+  static common::PlatformResult SetLedOnPeriodFromJson(const picojson::value& noti_value,
+                                                       notification_h noti_handle);
+  static common::PlatformResult SetLedOffPeriodFromJson(const picojson::value& noti_value,
+                                                        notification_h noti_handle);
+  static common::PlatformResult SetProgressTypeAndValueFromJson(const picojson::value& noti_value,
+                                                                bool is_update,
+                                                                notification_h noti_handle);
+  static common::PlatformResult SetAppControlInfoFromJson(const picojson::value& noti_value,
+                                                          notification_h noti_handle);
+  static common::PlatformResult SetEventsNumberFromJson(const picojson::value& noti_value,
+                                                        const std::string& key,
+                                                        notification_h noti_handle);
+  static common::PlatformResult SetDetailInfosFromJson(const picojson::value& noti_value,
+                                                       notification_h noti_handle);
+  static common::PlatformResult SetVibrationFromJson(const picojson::value& noti_value,
+                                                     notification_h noti_handle);
+  static common::PlatformResult SetSoundPathFromJson(const picojson::value& noti_value,
+                                                     notification_h noti_handle);
+  static common::PlatformResult SetPathsArrayFromJson(const picojson::value& noti_value,
+                                                      ImageEnumMap map, const std::string& key,
+                                                      notification_h noti_handle);
+  static common::PlatformResult SetTextsArrayFromJson(const picojson::value& noti_value,
+                                                      InformationEnumMap map,
+                                                      const std::string& key,
+                                                      notification_h noti_handle);
+  static common::PlatformResult SetTextFromJson(const picojson::value& noti_value,
+                                                notification_text_type_e type,
+                                                const std::string& key, notification_h noti_handle);
+
+  static common::PlatformResult PostNotification(const picojson::object& args, bool is_update,
+                                                 picojson::object* out_ptr,
+                                                 GetHandleFromJsonFun getHandle);
+
+ protected:
+  CommonNotification();
+  virtual ~CommonNotification();
+};
+
+}  // namespace notification
+}  // namespace extension
+
+#endif /* NOTIFICATION_COMMON_NOTIFICATION_H_ */
index 9c219a8..32a8fd9 100755 (executable)
         'notification_manager.h',
         'notification_manager.cc',
         'status_notification.cc',
-        'status_notification.h'
+        'status_notification.h',
+        'user_notification.cc',
+        'user_notification.h',
+        'common_notification.cc',
+        'common_notification.h'
       ],
       'conditions': [
         ['tizen == 1', {
             'packages': [
               'notification',
               'capi-system-device',
+              'capi-appfw-app-control',
             ]
           },
         }],
       ],
+      'direct_dependent_settings': {
+        'libraries' : [
+          '-ltizen_notification',
+        ],
+      },
     },
   ],
 }
index 252e755..6679ab3 100644 (file)
@@ -69,6 +69,13 @@ var StatusNotificationType = {
     PROGRESS: 'PROGRESS'
 };
 
+var UserNotificationType = {
+    SIMPLE: 'SIMPLE',
+    THUMBNAIL: 'THUMBNAIL',
+    ONGOING: 'ONGOING',
+    PROGRESS: 'PROGRESS'
+};
+
 var NotificationProgressType = {
     PERCENTAGE: 'PERCENTAGE',
     BYTE: 'BYTE'
@@ -83,10 +90,19 @@ function NotificationManager() {}
 
 NotificationManager.prototype.post = function(notification) {
     var args = validator_.validateArgs(arguments, [
-        { name: 'notification', type: types_.PLATFORM_OBJECT, values: StatusNotification }
+        { name: 'notification', type: types_.PLATFORM_OBJECT, values: Notification }
     ]);
 
+    if (args.notification instanceof tizen.StatusNotification) {
+        utils_.warn(
+            'DEPRECATION WARNING: StatusNotification is deprecated since Tizen 4.0. ' +
+                'Use UserNotification instead.'
+        );
+    }
+
     var data = {
+        //add marker for UserNotification implementation
+        newImpl: args.notification instanceof tizen.UserNotification,
         notification: args.notification
     };
 
@@ -106,7 +122,7 @@ NotificationManager.prototype.post = function(notification) {
 
 NotificationManager.prototype.update = function(notification) {
     var args = validator_.validateArgs(arguments, [
-        { name: 'notification', type: types_.PLATFORM_OBJECT, values: StatusNotification }
+        { name: 'notification', type: types_.PLATFORM_OBJECT, values: Notification }
     ]);
 
     if (!arguments.length) {
@@ -116,7 +132,16 @@ NotificationManager.prototype.update = function(notification) {
         throw new WebAPIException(WebAPIException.UNKNOWN_ERR);
     }
 
+    if (args.notification instanceof tizen.StatusNotification) {
+        utils_.warn(
+            'DEPRECATION WARNING: StatusNotification is deprecated since Tizen 4.0. ' +
+                'Use UserNotification instead.'
+        );
+    }
+
     var data = {
+        //add marker for UserNotification implementation
+        newImpl: args.notification instanceof tizen.UserNotification,
         notification: args.notification
     };
 
@@ -156,6 +181,11 @@ NotificationManager.prototype.removeAll = function() {
 NotificationManager.prototype.get = function(id) {
     var args = validator_.validateArgs(arguments, [{ name: 'id', type: types_.STRING }]);
 
+    utils_.warn(
+        'DEPRECATION WARNING: get() is deprecated since Tizen 4.0. ' +
+            'Use getNotification() instead.'
+    );
+
     if (!arguments.length) {
         throw new WebAPIException(WebAPIException.NOT_FOUND_ERR);
     }
@@ -179,7 +209,40 @@ NotificationManager.prototype.get = function(id) {
     return returnObject;
 };
 
+NotificationManager.prototype.getNotification = function(id) {
+    var args = validator_.validateArgs(arguments, [{ name: 'id', type: types_.STRING }]);
+
+    if (!arguments.length) {
+        throw new WebAPIException(WebAPIException.NOT_FOUND_ERR);
+    }
+
+    var data = {
+        //add marker for UserNotification implementation
+        newImpl: true,
+        id: args.id
+    };
+
+    var result = native_.callSync('NotificationManager_get', data);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+
+    var n = native_.getResultObject(result);
+
+    _edit.allow();
+    var returnObject = new UserNotification(n.userType, n.title, n);
+    _edit.disallow();
+
+    return returnObject;
+};
+
 NotificationManager.prototype.getAll = function() {
+    utils_.warn(
+        'DEPRECATION WARNING: getAll() is deprecated since Tizen 4.0. ' +
+            'Use getAllNotifications() instead.'
+    );
+
     var result = native_.callSync('NotificationManager_getAll', {});
 
     if (native_.isFailure(result)) {
@@ -198,6 +261,28 @@ NotificationManager.prototype.getAll = function() {
     return notifications;
 };
 
+NotificationManager.prototype.getAllNotifications = function() {
+    var result = native_.callSync('NotificationManager_getAll', {
+        //add marker for UserNotification implementation
+        newImpl: true
+    });
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+
+    var n = native_.getResultObject(result);
+    var notifications = [];
+
+    _edit.allow();
+    for (var i = 0; i < n.length; i++) {
+        notifications.push(new UserNotification(n[i].userType, n[i].title, n[i]));
+    }
+    _edit.disallow();
+
+    return notifications;
+};
+
 /**
  * Plays the custom effect of the service LED that is located to the front of a device.
  *
@@ -245,6 +330,105 @@ NotificationManager.prototype.stopLEDCustomEffect = function() {
     }
 };
 
+NotificationManager.prototype.saveNotificationAsTemplate = function(name, notification) {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'name', type: types_.STRING },
+        { name: 'notification', type: types_.PLATFORM_OBJECT, values: Notification }
+    ]);
+
+    //add marker for UserNotification implementation
+    args.newImpl = args.notification instanceof tizen.UserNotification;
+
+    var result = native_.callSync('NotificationManager_saveNotificationAsTemplate', args);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+};
+
+NotificationManager.prototype.createNotificationFromTemplate = function(name) {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'name', type: types_.STRING }
+    ]);
+
+    if (!arguments.length) {
+        throw new WebAPIException(WebAPIException.NOT_FOUND_ERR);
+    }
+
+    var result = native_.callSync(
+        'NotificationManager_createNotificationFromTemplate',
+        args
+    );
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+    var n = native_.getResultObject(result);
+
+    _edit.allow();
+    var returnObject = new UserNotification(n.userType, n.title, n);
+    _edit.disallow();
+
+    return returnObject;
+};
+
+var _checkProgressValue = function(v, _progressType) {
+    if (
+        (_progressType === NotificationProgressType.PERCENTAGE && (v >= 0 && v <= 100)) ||
+        (_progressType === NotificationProgressType.BYTE &&
+            converter_.toUnsignedLong(v) >= 0)
+    ) {
+        return true;
+    }
+    return false;
+};
+
+var _checkDetailInfo = function(v) {
+    if (type_.isNull(v)) {
+        return true;
+    }
+    if (!type_.isArray(v)) {
+        return false;
+    }
+    for (var i = 0; i < v.length; ++i) {
+        if (!(v[i] instanceof tizen.NotificationDetailInfo)) {
+            return false;
+        }
+    }
+    return true;
+};
+
+var _setDetailInfo = function(v) {
+    var _d = [];
+    for (var i = 0; i < v.length; ++i) {
+        _d.push(new tizen.NotificationDetailInfo(v[i].mainText, v[i].subText || null));
+    }
+    return _d;
+};
+
+var _checkStringArray = function(v) {
+    if (type_.isNull(v)) {
+        return true;
+    }
+    if (!type_.isArray(v)) {
+        return false;
+    }
+    for (var i = 0; i < v.length; ++i) {
+        if (!type_.isString(v[i])) {
+            return false;
+        }
+    }
+    return true;
+};
+
+var _isHex = function(v) {
+    return (
+        v.length === 7 &&
+        v.substr(0, 1) === '#' &&
+        /^([0-9A-Fa-f]{2})+$/.test(v.substr(1, 7))
+    );
+};
+
 function NotificationInitDict(data) {
     var _iconPath = null;
     var _soundPath = null;
@@ -253,69 +437,14 @@ function NotificationInitDict(data) {
     var _appId = null;
     var _progressType = NotificationProgressType.PERCENTAGE;
     var _progressValue = null;
-    var checkProgressValue = function(v) {
-        if (
-            (_progressType === NotificationProgressType.PERCENTAGE &&
-                (v >= 0 && v <= 100)) ||
-            (_progressType === NotificationProgressType.BYTE &&
-                converter_.toUnsignedLong(v) >= 0)
-        ) {
-            return true;
-        }
-        return false;
-    };
     var _number = null;
     var _subIconPath = null;
     var _detailInfo = [];
-    var checkDetailInfo = function(v) {
-        if (type_.isNull(v)) {
-            return true;
-        }
-        if (!type_.isArray(v)) {
-            return false;
-        }
-        for (var i = 0; i < v.length; ++i) {
-            if (!(v[i] instanceof tizen.NotificationDetailInfo)) {
-                return false;
-            }
-        }
-        return true;
-    };
-    var setDetailInfo = function(v) {
-        var _d = [];
-        for (var i = 0; i < v.length; ++i) {
-            _d.push(
-                new tizen.NotificationDetailInfo(v[i].mainText, v[i].subText || null)
-            );
-        }
-        return _d;
-    };
     var _ledColor = null;
-    var isHex = function(v) {
-        return (
-            v.length === 7 &&
-            v.substr(0, 1) === '#' &&
-            /^([0-9A-Fa-f]{2})+$/.test(v.substr(1, 7))
-        );
-    };
     var _ledOnPeriod = 0;
     var _ledOffPeriod = 0;
     var _backgroundImagePath = null;
     var _thumbnails = [];
-    var checkThumbnails = function(v) {
-        if (type_.isNull(v)) {
-            return true;
-        }
-        if (!type_.isArray(v)) {
-            return false;
-        }
-        for (var i = 0; i < v.length; ++i) {
-            if (!type_.isString(v[i])) {
-                return false;
-            }
-        }
-        return true;
-    };
 
     Object.defineProperties(this, {
         iconPath: {
@@ -402,7 +531,7 @@ function NotificationInitDict(data) {
                     _progressValue = v;
                     return;
                 }
-                if (checkProgressValue(v)) {
+                if (_checkProgressValue(v, _progressType)) {
                     _progressValue =
                         _progressType === NotificationProgressType.PERCENTAGE
                             ? v / 100
@@ -436,8 +565,8 @@ function NotificationInitDict(data) {
             set: function(v) {
                 _detailInfo =
                     _edit.canEdit && v
-                        ? setDetailInfo(v)
-                        : checkDetailInfo(v)
+                        ? _setDetailInfo(v)
+                        : _checkDetailInfo(v)
                             ? v
                             : _detailInfo;
             },
@@ -449,7 +578,7 @@ function NotificationInitDict(data) {
             },
             set: function(v) {
                 _ledColor =
-                    (type_.isString(v) && isHex(v)) || type_.isNull(v) ? v : _ledColor;
+                    (type_.isString(v) && _isHex(v)) || type_.isNull(v) ? v : _ledColor;
             },
             enumerable: true
         },
@@ -486,7 +615,7 @@ function NotificationInitDict(data) {
                 return _thumbnails;
             },
             set: function(v) {
-                _thumbnails = checkThumbnails(v) ? v : _thumbnails;
+                _thumbnails = _checkStringArray(v) ? v : _thumbnails;
             },
             enumerable: true
         }
@@ -575,6 +704,11 @@ function StatusNotification(statusType, title, notificationInitDict) {
     NotificationInitDict.call(this, notificationInitDict);
     Notification.call(this, notificationInitDict);
 
+    utils_.warn(
+        'DEPRECATION WARNING: StatusNotification is deprecated since Tizen 4.0. ' +
+            'Use UserNotification instead.'
+    );
+
     var _statusType =
         Object.keys(StatusNotificationType).indexOf(statusType) >= 0
             ? statusType
@@ -627,6 +761,511 @@ function NotificationDetailInfo(mainText, subText) {
     });
 }
 
+function TextContentsInitDict(data) {
+    if (!this) return;
+    var _progressType = NotificationProgressType.PERCENTAGE;
+    var _progressValue = null;
+    var _number = null;
+    var _detailInfo = [];
+    var _buttonsTexts = [];
+    var _contentForOff = null;
+
+    Object.defineProperties(this, {
+        progressType: {
+            get: function() {
+                return _progressType;
+            },
+            set: function(v) {
+                _progressType =
+                    Object.keys(NotificationProgressType).indexOf(v) >= 0
+                        ? v
+                        : _progressType;
+            },
+            enumerable: true
+        },
+        progressValue: {
+            get: function() {
+                if (null === _progressValue) {
+                    return _progressValue;
+                }
+
+                return _progressType === NotificationProgressType.PERCENTAGE
+                    ? _progressValue * 100
+                    : _progressValue;
+            },
+            set: function(v) {
+                if (type_.isNull(v)) {
+                    _progressValue = v;
+                    return;
+                }
+                if (_checkProgressValue(v, _progressType)) {
+                    _progressValue =
+                        _progressType === NotificationProgressType.PERCENTAGE
+                            ? v / 100
+                            : converter_.toUnsignedLong(v);
+                }
+            },
+            enumerable: true
+        },
+        eventsNumber: {
+            get: function() {
+                return _number;
+            },
+            set: function(v) {
+                _number = type_.isNumber(v) || type_.isNull(v) ? v : _number;
+            },
+            enumerable: true
+        },
+        detailInfo: {
+            get: function() {
+                return _detailInfo;
+            },
+            set: function(v) {
+                _detailInfo =
+                    _edit.canEdit && v
+                        ? _setDetailInfo(v)
+                        : _checkDetailInfo(v)
+                            ? v
+                            : _detailInfo;
+            },
+            enumerable: true
+        },
+        buttonsTexts: {
+            get: function() {
+                return _buttonsTexts;
+            },
+            set: function(v) {
+                _buttonsTexts = _checkStringArray(v) ? v : _buttonsTexts;
+            },
+            enumerable: true
+        },
+        contentForOff: {
+            get: function() {
+                return _contentForOff;
+            },
+            set: function(v) {
+                _contentForOff =
+                    type_.isString(v) || type_.isNull(v) ? v : _contentForOff;
+            },
+            enumerable: true
+        }
+    });
+
+    if (data instanceof _global.Object) {
+        this['progressType'] = data['progressType'];
+        for (var prop in data) {
+            if (this.hasOwnProperty(prop)) {
+                this[prop] = data[prop];
+            }
+        }
+    }
+}
+
+function ImagesInitDict(data) {
+    if (!this) return;
+    var _iconPath = null;
+    var _subIconPath = null;
+    var _indicatorIconPath = null;
+    var _lockScreenIconPath = null;
+    var _buttonIconPaths = [];
+    var _backgroundImagePath = null;
+
+    Object.defineProperties(this, {
+        iconPath: {
+            get: function() {
+                return _iconPath;
+            },
+            set: function(v) {
+                _iconPath = type_.isString(v) || type_.isNull(v) ? v : _iconPath;
+            },
+            enumerable: true
+        },
+        subIconPath: {
+            get: function() {
+                return _subIconPath;
+            },
+            set: function(v) {
+                _subIconPath = type_.isString(v) || type_.isNull(v) ? v : _subIconPath;
+            },
+            enumerable: true
+        },
+        indicatorIconPath: {
+            get: function() {
+                return _indicatorIconPath;
+            },
+            set: function(v) {
+                _indicatorIconPath =
+                    type_.isString(v) || type_.isNull(v) ? v : _indicatorIconPath;
+            },
+            enumerable: true
+        },
+        lockScreenIconPath: {
+            get: function() {
+                return _lockScreenIconPath;
+            },
+            set: function(v) {
+                _lockScreenIconPath =
+                    type_.isString(v) || type_.isNull(v) ? v : _lockScreenIconPath;
+            },
+            enumerable: true
+        },
+        buttonIconPaths: {
+            get: function() {
+                return _buttonIconPaths;
+            },
+            set: function(v) {
+                _buttonIconPaths = _checkStringArray(v) ? v : _buttonIconPaths;
+            },
+            enumerable: true
+        },
+        backgroundImagePath: {
+            get: function() {
+                return _backgroundImagePath;
+            },
+            set: function(v) {
+                _backgroundImagePath =
+                    type_.isString(v) || type_.isNull(v) ? v : _backgroundImagePath;
+            },
+            enumerable: true
+        }
+    });
+
+    if (data instanceof _global.Object) {
+        for (var prop in data) {
+            if (this.hasOwnProperty(prop)) {
+                this[prop] = data[prop];
+            }
+        }
+    }
+}
+
+function ThumbnailsInitDict(data) {
+    if (!this) return;
+    var _lockScreenThumbnailIconPath = null;
+    var _thumbnailIconPath = null;
+    var _thumbnails = [];
+
+    Object.defineProperties(this, {
+        lockScreenThumbnailIconPath: {
+            get: function() {
+                return _lockScreenThumbnailIconPath;
+            },
+            set: function(v) {
+                _lockScreenThumbnailIconPath =
+                    type_.isString(v) || type_.isNull(v)
+                        ? v
+                        : _lockScreenThumbnailIconPath;
+            },
+            enumerable: true
+        },
+        thumbnailIconPath: {
+            get: function() {
+                return _thumbnailIconPath;
+            },
+            set: function(v) {
+                _thumbnailIconPath =
+                    type_.isString(v) || type_.isNull(v) ? v : _thumbnailIconPath;
+            },
+            enumerable: true
+        },
+        thumbnails: {
+            get: function() {
+                return _thumbnails;
+            },
+            set: function(v) {
+                _thumbnails = _checkStringArray(v) ? v : _thumbnails;
+            },
+            enumerable: true
+        }
+    });
+
+    if (data instanceof _global.Object) {
+        for (var prop in data) {
+            if (this.hasOwnProperty(prop)) {
+                this[prop] = data[prop];
+            }
+        }
+    }
+}
+
+function ActionsInitDict(data) {
+    if (!this) return;
+    var _soundPath = null;
+    var _vibration = false;
+    var _appControl = null;
+    var _appId = null;
+
+    Object.defineProperties(this, {
+        soundPath: {
+            get: function() {
+                return _soundPath;
+            },
+            set: function(v) {
+                _soundPath = type_.isString(v) || type_.isNull(v) ? v : _soundPath;
+            },
+            enumerable: true
+        },
+        vibration: {
+            get: function() {
+                return _vibration;
+            },
+            set: function(v) {
+                _vibration = type_.isBoolean(v) ? v : _vibration;
+            },
+            enumerable: true
+        },
+        appControl: {
+            get: function() {
+                return _appControl;
+            },
+            set: function(v) {
+                _appControl =
+                    _edit.canEdit && v
+                        ? new tizen.ApplicationControl(
+                            v.operation,
+                            v.uri || null,
+                            v.mime || null,
+                            v.category || null,
+                            v.data || []
+                        )
+                        : v instanceof tizen.ApplicationControl || type_.isNull(v)
+                            ? v
+                            : _appControl;
+            },
+            enumerable: true
+        },
+        appId: {
+            get: function() {
+                return _appId;
+            },
+            set: function(v) {
+                _appId =
+                    (type_.isString(v) && !/\s/.test(v)) || type_.isNull(v) ? v : _appId;
+            },
+            enumerable: true
+        }
+    });
+
+    if (data instanceof _global.Object) {
+        for (var prop in data) {
+            if (this.hasOwnProperty(prop)) {
+                this[prop] = data[prop];
+            }
+        }
+    }
+}
+
+function GroupContentsInitDict(data) {
+    if (!this) return;
+    var _groupTitle = null;
+    var _groupContent = null;
+    var _groupContentForOff = null;
+
+    Object.defineProperties(this, {
+        groupTitle: {
+            get: function() {
+                return _groupTitle;
+            },
+            set: function(v) {
+                _groupTitle = type_.isString(v) || type_.isNull(v) ? v : _groupTitle;
+            },
+            enumerable: true
+        },
+        groupContent: {
+            get: function() {
+                return _groupContent;
+            },
+            set: function(v) {
+                _groupContent = type_.isString(v) || type_.isNull(v) ? v : _groupContent;
+            },
+            enumerable: true
+        },
+        groupContentForOff: {
+            get: function() {
+                return _groupContentForOff;
+            },
+            set: function(v) {
+                _groupContentForOff =
+                    type_.isString(v) || type_.isNull(v) ? v : _groupContentForOff;
+            },
+            enumerable: true
+        }
+    });
+
+    if (data instanceof _global.Object) {
+        for (var prop in data) {
+            if (this.hasOwnProperty(prop)) {
+                this[prop] = data[prop];
+            }
+        }
+    }
+}
+
+function LedsInitDict(data) {
+    if (!this) return;
+    var _ledColor = null;
+    var _ledOnPeriod = 0;
+    var _ledOffPeriod = 0;
+
+    Object.defineProperties(this, {
+        ledColor: {
+            get: function() {
+                return _ledColor;
+            },
+            set: function(v) {
+                _ledColor =
+                    (type_.isString(v) && _isHex(v)) || type_.isNull(v) ? v : _ledColor;
+            },
+            enumerable: true
+        },
+        ledOnPeriod: {
+            get: function() {
+                return _ledOnPeriod;
+            },
+            set: function(v) {
+                _ledOnPeriod = type_.isNumber(v) ? v : _ledOnPeriod;
+            },
+            enumerable: true
+        },
+        ledOffPeriod: {
+            get: function() {
+                return _ledOffPeriod;
+            },
+            set: function(v) {
+                _ledOffPeriod = type_.isNumber(v) ? v : _ledOffPeriod;
+            },
+            enumerable: true
+        }
+    });
+
+    if (data instanceof _global.Object) {
+        for (var prop in data) {
+            if (this.hasOwnProperty(prop)) {
+                this[prop] = data[prop];
+            }
+        }
+    }
+}
+
+function UserNotification(userType, title, notificationGroupedInitDict) {
+    validator_.isConstructorCall(this, UserNotification);
+    type_.isObject(notificationGroupedInitDict)
+        ? (notificationGroupedInitDict.title = title)
+        : (notificationGroupedInitDict = { title: title });
+    UserNotificationInitDict.call(this, notificationGroupedInitDict);
+    Notification.call(this, notificationGroupedInitDict);
+
+    this.textContents = new TextContentsInitDict(
+        notificationGroupedInitDict.textContents
+    );
+    this.images = new ImagesInitDict(notificationGroupedInitDict.images);
+    this.thumbnails = new ThumbnailsInitDict(notificationGroupedInitDict.thumbnails);
+    this.actions = new ActionsInitDict(notificationGroupedInitDict.actions);
+    this.leds = new LedsInitDict(notificationGroupedInitDict.leds);
+    this.groupContents = new GroupContentsInitDict(
+        notificationGroupedInitDict.groupContents
+    );
+
+    var _userType =
+        Object.keys(UserNotificationType).indexOf(userType) >= 0
+            ? userType
+            : StatusNotificationType.SIMPLE;
+
+    Object.defineProperties(this, {
+        userType: {
+            get: function() {
+                return _userType;
+            },
+            set: function(v) {
+                _userType =
+                    Object.keys(StatusNotificationType).indexOf(v) >= 0 && _edit.canEdit
+                        ? v
+                        : _userType;
+            },
+            enumerable: true
+        }
+    });
+}
+
+UserNotification.prototype = new Notification();
+UserNotification.prototype.constructor = UserNotification;
+
+function UserNotificationInitDict(data) {
+    var _textContents = null;
+    var _images = null;
+    var _thumbnails = null;
+    var _actions = null;
+    var _groupContents = null;
+    var _leds = null;
+
+    Object.defineProperties(this, {
+        textContents: {
+            get: function() {
+                return _textContents;
+            },
+            set: function(v) {
+                _textContents = type_.isObject(v) || type_.isNull(v) ? v : _textContents;
+            },
+            enumerable: true
+        },
+        images: {
+            get: function() {
+                return _images;
+            },
+            set: function(v) {
+                _images = type_.isObject(v) || type_.isNull(v) ? v : _images;
+            },
+            enumerable: true
+        },
+        thumbnails: {
+            get: function() {
+                return _thumbnails;
+            },
+            set: function(v) {
+                _thumbnails = type_.isObject(v) || type_.isNull(v) ? v : _thumbnails;
+            },
+            enumerable: true
+        },
+        actions: {
+            get: function() {
+                return _actions;
+            },
+            set: function(v) {
+                _actions = type_.isObject(v) || type_.isNull(v) ? v : _actions;
+            },
+            enumerable: true
+        },
+        groupContents: {
+            get: function() {
+                return _groupContents;
+            },
+            set: function(v) {
+                _groupContents =
+                    type_.isObject(v) || type_.isNull(v) ? v : _groupContents;
+            },
+            enumerable: true
+        },
+        leds: {
+            get: function() {
+                return _leds;
+            },
+            set: function(v) {
+                _leds = type_.isObject(v) || type_.isNull(v) ? v : _leds;
+            },
+            enumerable: true
+        }
+    });
+
+    if (data instanceof _global.Object) {
+        for (var prop in data) {
+            if (this.hasOwnProperty(prop)) {
+                this[prop] = data[prop];
+            }
+        }
+    }
+}
+
 exports = new NotificationManager();
 tizen.StatusNotification = StatusNotification;
+tizen.UserNotification = UserNotification;
 tizen.NotificationDetailInfo = NotificationDetailInfo;
index 5a86476..2a9495c 100644 (file)
@@ -28,7 +28,8 @@ NotificationExtension::NotificationExtension() {
   SetExtensionName("tizen.notification");
   SetJavaScriptAPI(kSource_notification_api);
 
-  const char* entry_points[] = {"tizen.StatusNotification", "tizen.NotificationDetailInfo", NULL};
+  const char* entry_points[] = {"tizen.StatusNotification", "tizen.UserNotification",
+                                "tizen.NotificationDetailInfo", NULL};
   SetExtraJSEntryPoints(entry_points);
 }
 
index a75aafa..32471a1 100644 (file)
@@ -16,8 +16,6 @@
 
 #include "notification/notification_instance.h"
 
-#include <functional>
-
 #include "common/logger.h"
 #include "common/picojson.h"
 #include "common/platform_result.h"
@@ -50,6 +48,9 @@ NotificationInstance::NotificationInstance() {
   REGISTER_SYNC("NotificationManager_removeAll", NotificationManagerRemoveAll);
   REGISTER_SYNC("NotificationManager_playLEDCustomEffect", NotificationManagerPlayLEDCustomEffect);
   REGISTER_SYNC("NotificationManager_stopLEDCustomEffect", NotificationManagerStopLEDCustomEffect);
+  REGISTER_SYNC("NotificationManager_saveNotificationAsTemplate", NotificationManagerSaveTemplate);
+  REGISTER_SYNC("NotificationManager_createNotificationFromTemplate",
+                NotificationManagerCreateFromTemplate);
 #undef REGISTER_SYNC
 
   manager_ = NotificationManager::GetInstance();
@@ -71,7 +72,20 @@ void NotificationInstance::NotificationManagerPost(const picojson::value& args,
   CHECK_PRIVILEGE_ACCESS(kPrivilegeNotification, &out);
 
   picojson::value val{picojson::object{}};
-  PlatformResult status = manager_->Post(args.get<picojson::object>(), val.get<picojson::object>());
+
+  using namespace std::placeholders;
+  std::function<PlatformResult(const picojson::object& args, picojson::object&)> impl{};
+  if (args.contains("newImpl") && args.get("newImpl").get<bool>()) {
+    LoggerD("New implementation");
+    impl = std::bind(&NotificationManager::PostUserNoti, manager_, _1, _2);
+  } else {
+    LoggerW(
+        "DEPRECATION WARNING: StatusNotification is deprecated since Tizen 4.0. Use "
+        "UserNotification instead.");
+    impl = std::bind(&NotificationManager::Post, manager_, _1, _2);
+  }
+
+  PlatformResult status = impl(args.get<picojson::object>(), val.get<picojson::object>());
 
   if (status.IsSuccess()) {
     ReportSuccess(val, out);
@@ -85,7 +99,19 @@ void NotificationInstance::NotificationManagerUpdate(const picojson::value& args
   ScopeLogger();
   CHECK_PRIVILEGE_ACCESS(kPrivilegeNotification, &out);
 
-  PlatformResult status = manager_->Update(args.get<picojson::object>());
+  using namespace std::placeholders;
+  std::function<PlatformResult(const picojson::object& args)> impl{};
+  if (args.contains("newImpl") && args.get("newImpl").get<bool>()) {
+    LoggerD("New implementation");
+    impl = std::bind(&NotificationManager::UpdateUserNoti, manager_, _1);
+  } else {
+    LoggerW(
+        "DEPRECATION WARNING: StatusNotification is deprecated since Tizen 4.0. Use "
+        "UserNotification instead.");
+    impl = std::bind(&NotificationManager::Update, manager_, _1);
+  }
+
+  PlatformResult status = impl(args.get<picojson::object>());
 
   if (status.IsSuccess()) {
     ReportSuccess(out);
@@ -125,9 +151,14 @@ void NotificationInstance::NotificationManagerRemoveAll(const picojson::value& a
 void NotificationInstance::NotificationManagerGet(const picojson::value& args,
                                                   picojson::object& out) {
   ScopeLogger();
+  LoggerW(
+      "DEPRECATION WARNING: get() is deprecated since Tizen 4.0. Use getNotifications() instead.");
+
   picojson::value val{picojson::object{}};
 
-  PlatformResult status = manager_->Get(args.get<picojson::object>(), val.get<picojson::object>());
+  PlatformResult status =
+      manager_->Get(args.get<picojson::object>(), val.get<picojson::object>(),
+                    args.contains("newImpl") && args.get("newImpl").get<bool>());
 
   if (status.IsSuccess()) {
     ReportSuccess(val, out);
@@ -139,9 +170,14 @@ void NotificationInstance::NotificationManagerGet(const picojson::value& args,
 void NotificationInstance::NotificationManagerGetAll(const picojson::value& args,
                                                      picojson::object& out) {
   ScopeLogger();
+  LoggerW(
+      "DEPRECATION WARNING: getAll() is deprecated since Tizen 4.0. Use getAllNotifications() "
+      "instead.");
+
   picojson::value val{picojson::array{}};
 
-  PlatformResult status = manager_->GetAll(val.get<picojson::array>());
+  PlatformResult status = manager_->GetAll(
+      val.get<picojson::array>(), args.contains("newImpl") && args.get("newImpl").get<bool>());
 
   if (status.IsSuccess()) {
     ReportSuccess(val, out);
@@ -178,6 +214,36 @@ void NotificationInstance::NotificationManagerStopLEDCustomEffect(const picojson
   }
 }
 
+void NotificationInstance::NotificationManagerSaveTemplate(const picojson::value& args,
+                                                           picojson::object& out) {
+  ScopeLogger();
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeNotification, &out);
+
+  PlatformResult status = manager_->SaveTemplate(args.get<picojson::object>());
+
+  if (status.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(status, &out);
+  }
+}
+
+void NotificationInstance::NotificationManagerCreateFromTemplate(const picojson::value& args,
+                                                                 picojson::object& out) {
+  ScopeLogger();
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeNotification, &out);
+  picojson::value val{picojson::object{}};
+
+  PlatformResult status =
+      manager_->CreateFromTemplate(args.get<picojson::object>(), val.get<picojson::object>());
+
+  if (status.IsSuccess()) {
+    ReportSuccess(val, out);
+  } else {
+    LogAndReportError(status, &out);
+  }
+}
+
 #undef CHECK_EXIST
 
 }  // namespace notification
index 5e33b04..fa0715f 100644 (file)
@@ -40,6 +40,8 @@ class NotificationInstance : public common::ParsedInstance {
 
   void NotificationManagerPlayLEDCustomEffect(const picojson::value& args, picojson::object& out);
   void NotificationManagerStopLEDCustomEffect(const picojson::value& args, picojson::object& out);
+  void NotificationManagerSaveTemplate(const picojson::value& args, picojson::object& out);
+  void NotificationManagerCreateFromTemplate(const picojson::value& args, picojson::object& out);
 };
 
 }  // namespace notification
index 47cedad..8d0a0e2 100644 (file)
@@ -19,6 +19,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 
+#include <app_common.h>
 #include <app_control_internal.h>
 #include <device/led.h>
 #include <notification_internal.h>
@@ -28,7 +29,9 @@
 #include "common/logger.h"
 #include "common/scope_exit.h"
 
+#include "notification/common_notification.h"
 #include "notification/status_notification.h"
+#include "notification/user_notification.h"
 
 namespace extension {
 namespace notification {
@@ -51,20 +54,31 @@ NotificationManager* NotificationManager::GetInstance() {
 
 PlatformResult NotificationManager::Post(const picojson::object& args, picojson::object& out) {
   ScopeLogger();
-  return StatusNotification::FromJson(args, false, &out);
+  return StatusNotification::PostStatusNotification(args, false, &out);
+}
+
+PlatformResult NotificationManager::PostUserNoti(const picojson::object& args,
+                                                 picojson::object& out) {
+  ScopeLogger();
+  return UserNotification::PostUserNotification(args, false, &out);
 }
 
 PlatformResult NotificationManager::Update(const picojson::object& args) {
   ScopeLogger();
-  return StatusNotification::FromJson(args, true, NULL);
+  return StatusNotification::PostStatusNotification(args, true, nullptr);
+}
+
+PlatformResult NotificationManager::UpdateUserNoti(const picojson::object& args) {
+  ScopeLogger();
+  return UserNotification::PostUserNotification(args, true, nullptr);
 }
 
 PlatformResult NotificationManager::Remove(const picojson::object& args) {
   ScopeLogger();
   int id = std::stoi(FromJson<std::string>(args, "id"));
 
-  int ret = notification_delete_by_priv_id(NULL, NOTIFICATION_TYPE_NONE, id);
-  if (ret != NOTIFICATION_ERROR_NONE) {
+  int ret = notification_delete_by_priv_id(nullptr, NOTIFICATION_TYPE_NONE, id);
+  if (NOTIFICATION_ERROR_NONE != ret) {
     return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Cannot remove notification error",
                               ("Cannot remove notification error: %d", ret));
   }
@@ -75,13 +89,13 @@ PlatformResult NotificationManager::Remove(const picojson::object& args) {
 PlatformResult NotificationManager::RemoveAll() {
   ScopeLogger();
   int ret = notification_delete_all(NOTIFICATION_TYPE_NOTI);
-  if (ret != NOTIFICATION_ERROR_NONE) {
+  if (NOTIFICATION_ERROR_NONE != ret) {
     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Notification noti remove all failed",
                               ("Notification remove all failed: %d", ret));
   }
 
   ret = notification_delete_all(NOTIFICATION_TYPE_ONGOING);
-  if (ret != NOTIFICATION_ERROR_NONE) {
+  if (NOTIFICATION_ERROR_NONE != ret) {
     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Notification ongoing remove all failed",
                               ("Notification remove all failed: %d", ret));
   }
@@ -89,7 +103,8 @@ PlatformResult NotificationManager::RemoveAll() {
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
-PlatformResult NotificationManager::Get(const picojson::object& args, picojson::object& out) {
+PlatformResult NotificationManager::Get(const picojson::object& args, picojson::object& out,
+                                        bool is_new_impl) {
   ScopeLogger();
   int id;
   try {
@@ -120,7 +135,12 @@ PlatformResult NotificationManager::Get(const picojson::object& args, picojson::
     LoggerE("Failed: GetAppControl");
     return status;
   }
-  status = StatusNotification::ToJson(id, noti_handle, app_control, &out);
+
+  if (!is_new_impl) {
+    status = StatusNotification::ToJson(id, noti_handle, app_control, &out);
+  } else {
+    status = UserNotification::ToJson(id, noti_handle, app_control, &out);
+  }
   if (status.IsError()) {
     LoggerE("Failed: ToJson");
     return status;
@@ -128,7 +148,7 @@ PlatformResult NotificationManager::Get(const picojson::object& args, picojson::
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
-PlatformResult NotificationManager::GetAll(picojson::array& out) {
+PlatformResult NotificationManager::GetAll(picojson::array& out, bool is_new_impl) {
   ScopeLogger();
   notification_h noti = nullptr;
   notification_list_h noti_list = nullptr;
@@ -160,7 +180,7 @@ PlatformResult NotificationManager::GetAll(picojson::array& out) {
     noti = notification_list_get_data(noti_list_iter);
     if (nullptr != noti) {
       int noti_priv = -1;
-      ret = notification_get_id(noti, NULL, &noti_priv);
+      ret = notification_get_id(noti, nullptr, &noti_priv);
       if (NOTIFICATION_ERROR_NONE != ret) {
         return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Cannot get notification id error",
                                   ("Cannot get notification id, error: %d", ret));
@@ -179,7 +199,11 @@ PlatformResult NotificationManager::GetAll(picojson::array& out) {
 
       picojson::object noti_item = picojson::object();
 
-      status = StatusNotification::ToJson(noti_priv, noti, app_control, &noti_item);
+      if (!is_new_impl) {
+        status = StatusNotification::ToJson(noti_priv, noti, app_control, &noti_item);
+      } else {
+        status = UserNotification::ToJson(noti_priv, noti, app_control, &noti_item);
+      }
       if (status.IsError()) return status;
 
       out.push_back(picojson::value(noti_item));
@@ -202,17 +226,17 @@ PlatformResult NotificationManager::PlayLEDCustomEffect(const picojson::object&
   unsigned int platformFlags = 0;
   for (auto flag : flags) {
     std::string flagStr = JsonCast<std::string>(flag);
-    if (flagStr == "LED_CUSTOM_DEFAULT")
+    if ("LED_CUSTOM_DEFAULT" == flagStr)
       platformFlags |= LED_CUSTOM_DEFAULT;
-    else if (flagStr == "LED_CUSTOM_DUTY_ON")
+    else if ("LED_CUSTOM_DUTY_ON" == flagStr)
       platformFlags |= LED_CUSTOM_DUTY_ON;
   }
 
   int ret;
   ret = device_led_play_custom(timeOn, timeOff, color, platformFlags);
-  if (ret != DEVICE_ERROR_NONE) {
+  if (DEVICE_ERROR_NONE != ret) {
     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Cannot play LED custom effect",
-                              ("Cannot play LED custom effect: ", ret));
+                              ("Cannot play LED custom effect: %d", ret));
   }
 
   return PlatformResult(ErrorCode::NO_ERROR);
@@ -222,11 +246,74 @@ PlatformResult NotificationManager::StopLEDCustomEffect() {
   ScopeLogger();
 
   int ret = device_led_stop_custom();
-  if (ret != DEVICE_ERROR_NONE) {
+  if (DEVICE_ERROR_NONE != ret) {
     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Cannot stop LED custom effect",
-                              ("Cannot stop LED custom effect: ", ret));
+                              ("Cannot stop LED custom effect: %d", ret));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+common::PlatformResult NotificationManager::SaveTemplate(const picojson::object& args) {
+  ScopeLogger();
+  std::string name = FromJson<std::string>(args, "name");
+  notification_h noti_handle = nullptr;
+  int ret;
+  SCOPE_EXIT {
+    notification_free(noti_handle);
+  };
+
+  PlatformResult status = PlatformResult(ErrorCode::NO_ERROR);
+  const auto& new_impl_it = args.find("newImpl");
+  const auto& noti_val_it = args.find("notification");
+  if (args.end() != new_impl_it && args.end() != noti_val_it && new_impl_it->second.get<bool>()) {
+    status = UserNotification::GetNotiHandleFromJson(noti_val_it->second, false, &noti_handle);
+  } else {
+    status = StatusNotification::GetNotiHandleFromJson(noti_val_it->second, false, &noti_handle);
+  }
+
+  if (status.IsError()) {
+    return status;
+  }
+
+  ret = notification_save_as_template(noti_handle, name.c_str());
+  if (NOTIFICATION_ERROR_NONE != ret) {
+    LoggerD("Error: %d (%s)", ret, get_error_message(ret));
+    if (NOTIFICATION_ERROR_MAX_EXCEEDED == ret) {
+      return LogAndCreateResult(ErrorCode::QUOTA_EXCEEDED_ERR,
+                                "Maximum number of templates exceeded",
+                                ("Maximum number of templates exceeded, error: %d", ret));
+    } else {
+      return LogAndCreateResult(ErrorCode::ABORT_ERR, "Saving template failed",
+                                ("Saving template failed, error: %d", ret));
+    }
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+common::PlatformResult NotificationManager::CreateFromTemplate(const picojson::object& args,
+                                                               picojson::object& out) {
+  ScopeLogger();
+  std::string name = FromJson<std::string>(args, "name");
+
+  notification_h noti_handle = nullptr;
+  noti_handle = notification_create_from_template(name.c_str());
+  if (!noti_handle) {
+    return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "The template with given name not found",
+                              ("The template with given name not found, handle is nullptr"));
   }
 
+  SCOPE_EXIT {
+    notification_free(noti_handle);
+  };
+
+  // This method is designed to return only UserNotification objects
+  PlatformResult status = UserNotification::ToJson(0, noti_handle, nullptr, &out);
+  if (status.IsError()) {
+    LoggerE("Failed: ToJson");
+    return status;
+  }
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
index df76d26..883ee57 100644 (file)
@@ -30,15 +30,22 @@ class NotificationManager {
   static NotificationManager* GetInstance();
 
   common::PlatformResult Post(const picojson::object& args, picojson::object& out);
+  common::PlatformResult PostUserNoti(const picojson::object& args, picojson::object& out);
   common::PlatformResult Update(const picojson::object& args);
+  common::PlatformResult UpdateUserNoti(const picojson::object& args);
   common::PlatformResult Remove(const picojson::object& args);
   common::PlatformResult RemoveAll();
-  common::PlatformResult Get(const picojson::object& args, picojson::object& out);
-  common::PlatformResult GetAll(picojson::array& out);
+  common::PlatformResult Get(const picojson::object& args, picojson::object& out,
+                             bool is_new_impl = false);
+  common::PlatformResult GetAll(picojson::array& out, bool is_new_impl = false);
 
   common::PlatformResult PlayLEDCustomEffect(const picojson::object& args);
   common::PlatformResult StopLEDCustomEffect();
 
+  // TODO needed also below functions for new design?
+  common::PlatformResult SaveTemplate(const picojson::object& args);
+  common::PlatformResult CreateFromTemplate(const picojson::object& args, picojson::object& out);
+
  private:
   NotificationManager();
   virtual ~NotificationManager();
index d018255..f4b002d 100644 (file)
 
 #include "notification/status_notification.h"
 
-#include <app_control_internal.h>
-#include <notification.h>
-#include <notification_internal.h>
-
 #include "common/converter.h"
 #include "common/filesystem/filesystem_provider.h"
 #include "common/logger.h"
@@ -30,23 +26,6 @@ namespace notification {
 
 using namespace common;
 
-const std::string kProgressTypePercentage = "PERCENTAGE";
-const std::string kProgressTypeByte = "BYTE";
-
-const InformationEnumMap StatusNotification::info_map_ = {{0, NOTIFICATION_TEXT_TYPE_INFO_1},
-                                                          {1, NOTIFICATION_TEXT_TYPE_INFO_2},
-                                                          {2, NOTIFICATION_TEXT_TYPE_INFO_3}};
-
-const InformationEnumMap StatusNotification::info_sub_map_ = {
-    {0, NOTIFICATION_TEXT_TYPE_INFO_SUB_1},
-    {1, NOTIFICATION_TEXT_TYPE_INFO_SUB_2},
-    {2, NOTIFICATION_TEXT_TYPE_INFO_SUB_3}};
-
-const ImageEnumMap StatusNotification::thumbnails_map_ = {{0, NOTIFICATION_IMAGE_TYPE_LIST_1},
-                                                          {1, NOTIFICATION_IMAGE_TYPE_LIST_2},
-                                                          {2, NOTIFICATION_IMAGE_TYPE_LIST_3},
-                                                          {3, NOTIFICATION_IMAGE_TYPE_LIST_4}};
-
 StatusNotification::StatusNotification() {
   ScopeLogger();
 }
@@ -55,1177 +34,151 @@ StatusNotification::~StatusNotification() {
   ScopeLogger();
 }
 
-bool StatusNotification::IsColorFormatNumberic(const std::string& color) {
-  ScopeLogger();
-  std::string hexCode = "0123456789abcdef";
-  if (color.length() != 7 || '#' != color[0]) {
-    return false;
-  }
-
-  for (size_t i = 1; i < color.length(); i++) {
-    if (std::string::npos == hexCode.find(color[i])) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-PlatformResult StatusNotification::SetLayout(notification_h noti_handle,
-                                             const std::string& noti_type) {
-  ScopeLogger();
-  notification_ly_type_e noti_layout = NOTIFICATION_LY_NONE;
-
-  if (noti_type == "SIMPLE") {
-    long number;
-    PlatformResult status = GetNumber(noti_handle, NOTIFICATION_TEXT_TYPE_EVENT_COUNT, &number);
-    if (status.IsError()) {
-      LoggerE("Failed: GetNumber");
-      return status;
-    }
-    if (number > 0)
-      noti_layout = NOTIFICATION_LY_NOTI_EVENT_MULTIPLE;
-    else
-      noti_layout = NOTIFICATION_LY_NOTI_EVENT_SINGLE;
-  } else if (noti_type == "THUMBNAIL") {
-    noti_layout = NOTIFICATION_LY_NOTI_THUMBNAIL;
-  }
-  if (noti_type == "ONGOING") {
-    noti_layout = NOTIFICATION_LY_ONGOING_EVENT;
-  } else if (noti_type == "PROGRESS") {
-    noti_layout = NOTIFICATION_LY_ONGOING_PROGRESS;
-  }
-  int ret = notification_set_layout(noti_handle, noti_layout);
-  if (ret != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification layout error",
-                              ("Set notification layout error: %d", ret));
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-static bool ServiceExtraDataCb(app_control_h service, const char* key, void* user_data) {
-  ScopeLogger();
-  if (nullptr == user_data || nullptr == key) {
-    LoggerE("User data or key not exist");
-    return true;
-  }
-
-  picojson::array* control_data = static_cast<picojson::array*>(user_data);
-
-  int length = 0;
-  char** value = NULL;
-  SCOPE_EXIT {
-    free(value);
-  };
-
-  int ret = app_control_get_extra_data_array(service, key, &value, &length);
-  if (ret != APP_CONTROL_ERROR_NONE) {
-    LoggerE("Get app control extra data error: %d", ret);
-    return true;
-  }
-
-  if (!value || !length) {
-    LoggerE("Get app control extra data value error");
-    return true;
-  }
-
-  picojson::array values = picojson::array();
-  for (int index = 0; index < length; ++index) {
-    values.push_back(picojson::value(value[index]));
-  }
-
-  picojson::object data_control_elem = picojson::object();
-  data_control_elem["key"] = picojson::value(key);
-  data_control_elem["value"] = picojson::value(values);
-
-  control_data->push_back(picojson::value(data_control_elem));
-
-  return true;
-}
-
-PlatformResult StatusNotification::Create(notification_type_e noti_type,
-                                          notification_h* noti_handle) {
-  ScopeLogger();
-  *noti_handle = notification_create(noti_type);
-  if (!*noti_handle) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Cannot make new notification object");
-  }
-
-  if (NOTIFICATION_TYPE_ONGOING == noti_type) {
-    int ret =
-        notification_set_display_applist(*noti_handle, NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY |
-                                                           NOTIFICATION_DISPLAY_APP_INDICATOR);
-    if (ret != NOTIFICATION_ERROR_NONE) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Cannot set notification display applist",
-                                ("Cannot make new notification object: %d", ret));
-    }
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::StatusTypeFromPlatform(notification_type_e noti_type,
-                                                          notification_ly_type_e noti_layout,
-                                                          std::string* type) {
-  ScopeLogger();
-  if (noti_type == NOTIFICATION_TYPE_NOTI) {
-    if (noti_layout == NOTIFICATION_LY_NOTI_EVENT_SINGLE ||
-        noti_layout == NOTIFICATION_LY_NOTI_EVENT_MULTIPLE) {
-      *type = "SIMPLE";
-    } else if (noti_layout == NOTIFICATION_LY_NOTI_THUMBNAIL) {
-      *type = "THUMBNAIL";
-    }
-  } else if (noti_type == NOTIFICATION_TYPE_ONGOING) {
-    if (noti_layout == NOTIFICATION_LY_ONGOING_EVENT) {
-      *type = "ONGOING";
-    } else if (noti_layout == NOTIFICATION_LY_ONGOING_PROGRESS) {
-      *type = "PROGRESS";
-    }
-  } else {
-    return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Notification type not found");
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::StatusTypeToPlatform(const std::string& type,
-                                                        notification_type_e* noti_type) {
-  ScopeLogger();
-  if (type == "SIMPLE" || type == "THUMBNAIL") {
-    *noti_type = NOTIFICATION_TYPE_NOTI;
-  } else if (type == "ONGOING" || type == "PROGRESS") {
-    *noti_type = NOTIFICATION_TYPE_ONGOING;
-  } else {
-    return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "Invalide notification type",
-                              ("Invalide noti type: %s", type.c_str()));
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetImage(notification_h noti_handle,
-                                            notification_image_type_e image_type,
-                                            std::string* image_path) {
-  ScopeLogger();
-  char* path = NULL;
-
-  *image_path = "";
-
-  if (notification_get_image(noti_handle, image_type, &path) != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification image error",
-                              ("Get notification image error, image_type: %d", image_type));
-  }
-  if (path) {
-    *image_path = path;
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetImage(notification_h noti_handle,
-                                            notification_image_type_e image_type,
-                                            const std::string& image_path) {
-  ScopeLogger();
-  int ret = notification_set_image(noti_handle, image_type, image_path.c_str());
-  if (ret != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(
-        ErrorCode::UNKNOWN_ERR, "Set notification image error",
-        ("Set notification image error, image_type: %d, error: %d", image_type, ret));
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetText(notification_h noti_handle,
-                                           notification_text_type_e text_type,
-                                           std::string* noti_text) {
-  ScopeLogger();
-  char* text = NULL;
-
-  *noti_text = "";
-
-  if (notification_get_text(noti_handle, text_type, &text) != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification text error",
-                              ("Get notification text error, text_type: %d", text_type));
-  }
-
-  if (text) *noti_text = text;
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetText(notification_h noti_handle,
-                                           notification_text_type_e text_type,
-                                           const std::string& noti_text) {
-  ScopeLogger();
-  int ret = notification_set_text(noti_handle, text_type, noti_text.c_str(), NULL,
-                                  NOTIFICATION_VARIABLE_TYPE_NONE);
-  if (ret != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(
-        ErrorCode::UNKNOWN_ERR, "Set notification text error",
-        ("Set notification text error, text_type: %d, error: %d", text_type, ret));
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetNumber(notification_h noti_handle,
-                                             notification_text_type_e text_type, long* number) {
-  ScopeLogger();
-  std::string text;
-  PlatformResult status = GetText(noti_handle, text_type, &text);
-  if (status.IsError()) return status;
-
-  if (text.length())
-    *number = std::stol(text);
-  else
-    *number = -1;
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetDetailInfos(notification_h noti_handle,
-                                                  picojson::array* out) {
-  ScopeLogger();
-  if (info_map_.size() != info_sub_map_.size()) {
-    return LogAndCreateResult(ErrorCode::VALIDATION_ERR,
-                              "Different notification information types element size");
-  }
-
-  picojson::value detail_info = picojson::value(picojson::object());
-  picojson::object& detail_info_obj = detail_info.get<picojson::object>();
-
-  std::string text;
-  size_t info_map_size = info_map_.size();
-  for (size_t idx = 0; idx < info_map_size; ++idx) {
-    PlatformResult status = GetText(noti_handle, info_map_.at(idx), &text);
-    if (status.IsError()) return status;
-
-    if (!text.length()) break;
-
-    detail_info_obj["mainText"] = picojson::value(text);
-
-    status = GetText(noti_handle, info_sub_map_.at(idx), &text);
-    if (status.IsError()) return status;
-
-    if (text.length()) {
-      detail_info_obj["subText"] = picojson::value(text);
-    }
-
-    out->push_back(detail_info);
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetDetailInfos(notification_h noti_handle,
-                                                  const picojson::array& value) {
-  ScopeLogger();
-  size_t idx = 0;
-
-  size_t info_map_size = info_map_.size();
-  for (auto& item : value) {
-    const picojson::object& obj = JsonCast<picojson::object>(item);
-
-    PlatformResult status =
-        SetText(noti_handle, info_map_.at(idx), common::FromJson<std::string>(obj, "mainText"));
-    if (status.IsError()) return status;
-
-    if (picojson::value(obj).contains("subText") && !IsNull(obj, "subText")) {
-      PlatformResult status = SetText(noti_handle, info_sub_map_.at(idx),
-                                      common::FromJson<std::string>(obj, "subText"));
-      if (status.IsError()) return status;
-    }
-
-    ++idx;
-
-    if (idx > info_map_size) {
-      return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR,
-                                "Too many values in notification detailInfo array");
-    }
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetLedColor(notification_h noti_handle, std::string* led_color) {
-  ScopeLogger();
-  unsigned int color = 0;
-  notification_led_op_e type = NOTIFICATION_LED_OP_ON;
-
-  if (notification_get_led(noti_handle, &type, (int*)&color) != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
-                              "Get notification led displaying option error");
-  }
-
-  *led_color = "";
-  std::stringstream stream;
-
-  if (NOTIFICATION_LED_OP_OFF != type) {
-    color = 0x00FFFFFF & color;
-    stream << std::hex << color;
-    *led_color = "#" + stream.str();
-
-    while (led_color->length() < 7) {
-      led_color->insert(1, "0");
-    }
-
-    std::transform(led_color->begin(), led_color->end(), led_color->begin(), ::tolower);
-  }
-
-  LoggerD("color:%s", (*led_color).c_str());
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetLedColor(notification_h noti_handle,
-                                               const std::string& led_color) {
-  ScopeLogger();
-  std::string color_str = led_color;
-  std::transform(color_str.begin(), color_str.end(), color_str.begin(), ::tolower);
-
-  if (!IsColorFormatNumberic(color_str)) {
-    return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Led color is not numeric value",
-                              ("Led color is not numeric value: %s", color_str.c_str()));
-  }
-
-  std::stringstream stream;
-  unsigned int color = 0;
-  notification_led_op_e type = NOTIFICATION_LED_OP_ON;
-  std::string color_code = color_str.substr(1, color_str.length()).insert(0, "ff");
-
-  stream << std::hex << color_code;
-  stream >> color;
-
-  if (color != 0)
-    type = NOTIFICATION_LED_OP_ON_CUSTOM_COLOR;
-  else
-    type = NOTIFICATION_LED_OP_OFF;
-
-  int ret = notification_set_led(noti_handle, type, static_cast<int>(color));
-  if (ret != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification led color eror",
-                              ("Set notification led color eror: %d", ret));
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetLedPeriod(notification_h noti_handle,
-                                                unsigned long* on_period,
-                                                unsigned long* off_period) {
-  ScopeLogger();
-  int on_time = 0;
-  int off_time = 0;
-
-  if (notification_get_led_time_period(noti_handle, &on_time, &off_time) !=
-      NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification led on/off period error");
-  }
-
-  if (on_period) *on_period = on_time;
-  if (off_period) *off_period = off_time;
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetLedOnPeriod(notification_h noti_handle,
-                                                  unsigned long on_period) {
-  ScopeLogger();
-  unsigned long off_period = 0;
-  PlatformResult status = GetLedPeriod(noti_handle, nullptr, &off_period);
-  if (status.IsError()) return status;
-
-  int ret = notification_set_led_time_period(noti_handle, on_period, off_period);
-  if (ret != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification led on period error",
-                              ("Set notification led on period error: %d", ret));
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetLedOffPeriod(notification_h noti_handle,
-                                                   unsigned long off_period) {
-  ScopeLogger();
-  unsigned long on_period = 0;
-  PlatformResult status = GetLedPeriod(noti_handle, &on_period, nullptr);
-  if (status.IsError()) return status;
-
-  int ret = notification_set_led_time_period(noti_handle, on_period, off_period);
-  if (ret != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification led off period error",
-                              ("Set notification led off period error: %d", ret));
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetThumbnails(notification_h noti_handle, picojson::array* out) {
-  ScopeLogger();
-  std::string text;
-  size_t thumbnails_map_size = thumbnails_map_.size();
-  for (size_t idx = 0; idx < thumbnails_map_size; ++idx) {
-    PlatformResult status = GetImage(noti_handle, thumbnails_map_.at(idx), &text);
-    if (status.IsError()) return status;
-
-    if (!text.length()) break;
-
-    // CHECK GetVirtualPath ??
-    out->push_back(picojson::value(common::FilesystemProvider::Create().GetVirtualPath(text)));
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetThumbnails(notification_h noti_handle,
-                                                 const picojson::array& value) {
-  ScopeLogger();
-  size_t idx = 0;
-
-  size_t thumbnails_map_size = thumbnails_map_.size();
-  for (auto& item : value) {
-    const std::string& text = JsonCast<std::string>(item);
-    std::string real_path = common::FilesystemProvider::Create().GetRealPath(text);
-
-    PlatformResult status = SetImage(noti_handle, thumbnails_map_.at(idx), real_path);
-    if (status.IsError()) return status;
-
-    ++idx;
-
-    if (idx > thumbnails_map_size) {
-      return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR,
-                                "Too many values in notification thumbnail array");
-    }
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetSoundPath(notification_h noti_handle,
-                                                std::string* sound_path) {
-  ScopeLogger();
-  *sound_path = "";
-
-  const char* path = NULL;
-  notification_sound_type_e type = NOTIFICATION_SOUND_TYPE_NONE;
-
-  if (notification_get_sound(noti_handle, &type, &path) != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification sound error");
-  }
-
-  LoggerD("Sound type = %d", type);
-
-  if (path && (type == NOTIFICATION_SOUND_TYPE_USER_DATA)) {
-    *sound_path = path;
-  }
-
-  LoggerD("Sound path = %s", sound_path->c_str());
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetSoundPath(notification_h noti_handle,
-                                                const std::string& sound_path) {
-  ScopeLogger();
-  int ret =
-      notification_set_sound(noti_handle, NOTIFICATION_SOUND_TYPE_USER_DATA, sound_path.c_str());
-  if (ret != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification sound error",
-                              ("Set notification sound error: %d", ret));
-  }
-
-  LoggerD("Sound path = %s", sound_path.c_str());
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetVibration(notification_h noti_handle, bool* vibration) {
-  ScopeLogger();
-  notification_vibration_type_e vib_type = NOTIFICATION_VIBRATION_TYPE_NONE;
-
-  if (notification_get_vibration(noti_handle, &vib_type, NULL) != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification vibration error");
-  }
-
-  if (NOTIFICATION_VIBRATION_TYPE_DEFAULT == vib_type ||
-      NOTIFICATION_VIBRATION_TYPE_USER_DATA == vib_type) {
-    *vibration = true;
-  } else {
-    *vibration = false;
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetVibration(notification_h noti_handle, bool vibration) {
-  ScopeLogger();
-  bool platform_vibration;
-  PlatformResult status = GetVibration(noti_handle, &platform_vibration);
-  if (status.IsError()) return status;
-
-  if (platform_vibration != vibration) {
-    notification_vibration_type_e vib_type = NOTIFICATION_VIBRATION_TYPE_NONE;
-
-    if (vibration) {
-      vib_type = NOTIFICATION_VIBRATION_TYPE_DEFAULT;
-    }
-
-    int ret = notification_set_vibration(noti_handle, vib_type, NULL);
-    if (ret != NOTIFICATION_ERROR_NONE) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification vibration error",
-                                ("Set notification vibration error: %d", ret));
-    }
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetApplicationControl(app_control_h app_handle,
-                                                         picojson::object* out_ptr) {
-  ScopeLogger();
-  picojson::object& out = *out_ptr;
-
-  char* operation = NULL;
-  char* uri = NULL;
-  char* mime = NULL;
-  char* category = NULL;
-  SCOPE_EXIT {
-    free(operation);
-    free(uri);
-    free(mime);
-    free(category);
-  };
-
-  int ret = app_control_get_operation(app_handle, &operation);
-  if (ret != APP_CONTROL_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get application control operation error",
-                              ("Get application control operation error: %d", ret));
-  }
-  if (operation) {
-    out["operation"] = picojson::value(operation);
-    LoggerD("operation = %s", operation);
-  }
-
-  if (app_control_get_uri(app_handle, &uri) != APP_CONTROL_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get application control uri error");
-  }
-  if (uri) {
-    out["uri"] = picojson::value(uri);
-    LoggerD("uri = %s", uri);
-  }
-
-  if (app_control_get_mime(app_handle, &mime) != APP_CONTROL_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get application control mime error");
-  }
-  if (mime) {
-    out["mime"] = picojson::value(mime);
-    LoggerD("mime = %s", mime);
-  }
-
-  if (app_control_get_category(app_handle, &category) != APP_CONTROL_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get application control category error");
-  }
-  if (category) {
-    out["category"] = picojson::value(category);
-    LoggerD("category = %s", category);
-  }
-
-  picojson::array app_control_data = picojson::array();
-  if (app_control_foreach_extra_data(app_handle, ServiceExtraDataCb, (void*)&app_control_data) !=
-      APP_CONTROL_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get application control data error");
-  }
-  out["data"] = picojson::value(app_control_data);
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetApplicationControl(app_control_h app_handle,
-                                                         const picojson::object& app_ctrl) {
-  ScopeLogger();
-  picojson::value val(app_ctrl);
-  const std::string& operation = common::FromJson<std::string>(app_ctrl, "operation");
-
-  int ret;
-  if (operation.length()) {
-    ret = app_control_set_operation(app_handle, operation.c_str());
-  } else {
-    ret = app_control_set_operation(app_handle, APP_CONTROL_OPERATION_DEFAULT);
-  }
-  if (ret != APP_CONTROL_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set application control operation error",
-                              ("Set application control operation error: %d", ret));
-  }
-
-  if (val.contains("uri") && !IsNull(app_ctrl, "uri")) {
-    const std::string& uri = common::FromJson<std::string>(app_ctrl, "uri");
-    ret = app_control_set_uri(app_handle, uri.c_str());
-    if (ret != APP_CONTROL_ERROR_NONE) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set application control uri error",
-                                ("Set application control uri error: %d", ret));
-    }
-  }
-
-  if (val.contains("mime") && !IsNull(app_ctrl, "mime")) {
-    const std::string& mime = common::FromJson<std::string>(app_ctrl, "mime");
-    ret = app_control_set_mime(app_handle, mime.c_str());
-    if (ret != APP_CONTROL_ERROR_NONE) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set application control mime error",
-                                ("Set application control mime error: %d", ret));
-    }
-  }
-
-  if (val.contains("category") && !IsNull(app_ctrl, "category")) {
-    const std::string& category = common::FromJson<std::string>(app_ctrl, "category");
-    ret = app_control_set_category(app_handle, category.c_str());
-    if (ret != APP_CONTROL_ERROR_NONE) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set application control category error",
-                                ("Set application control category error: %d", ret));
-    }
-  }
-
-  if (!picojson::value(app_ctrl).contains("data") || IsNull(app_ctrl, "data")) {
-    return PlatformResult(ErrorCode::NO_ERROR);
-  }
-
-  auto& items = common::FromJson<picojson::array>(app_ctrl, "data");
-
-  int idx = 0;
-
-  for (auto item : items) {
-    const picojson::object& obj = JsonCast<picojson::object>(item);
-    const std::string key = common::FromJson<std::string>(obj, "key");
-    const picojson::array values = common::FromJson<picojson::array>(obj, "value");
-    const char** arrayValue = (const char**)calloc(sizeof(char*), values.size());
-    SCOPE_EXIT {
-      free(arrayValue);
-    };
-    idx = 0;
-    for (auto& item : values) {
-      arrayValue[idx] = JsonCast<std::string>(item).c_str();
-      ++idx;
-    }
-    ret = app_control_add_extra_data_array(app_handle, key.c_str(), arrayValue, values.size());
-    if (ret != APP_CONTROL_ERROR_NONE) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set application control extra data error",
-                                ("Set application control extra data error: %d", ret));
-    }
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetApplicationId(app_control_h app_handle, std::string* app_id) {
-  ScopeLogger();
-  char* app_id_str = NULL;
-  SCOPE_EXIT {
-    free(app_id_str);
-  };
-
-  *app_id = "";
-
-  if (app_control_get_app_id(app_handle, &app_id_str) != APP_CONTROL_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get applicaiton ID failed");
-  }
-
-  if (app_id_str != NULL) {
-    *app_id = app_id_str;
-  }
-
-  LoggerD("Get appId = %s", /*(*app_id).c_str()*/ app_id_str);
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetApplicationId(app_control_h app_handle,
-                                                    const std::string& app_id) {
-  ScopeLogger();
-  int ret = app_control_set_app_id(app_handle, app_id.c_str());
-  if (ret != APP_CONTROL_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set applicaiton ID error",
-                              ("Set applicaiton ID error: %d", ret));
-  }
-
-  LoggerD("Set appId = %s", app_id.c_str());
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetProgressValue(notification_h noti_handle,
-                                                    const std::string& progess_type,
-                                                    double* progress_value) {
-  ScopeLogger();
-  double tmp_progress_value = 0.0;
-
-  if (progess_type == kProgressTypeByte) {
-    if (notification_get_size(noti_handle, &tmp_progress_value) != NOTIFICATION_ERROR_NONE) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification size error");
-    }
-  } else if (progess_type == kProgressTypePercentage) {
-    if (notification_get_progress(noti_handle, &tmp_progress_value) != NOTIFICATION_ERROR_NONE) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification progress error");
-    }
-    // native api uses range 0-1, but webapi expects 0-100, so we need to multiply result with 100
-    tmp_progress_value *= 100;
-  } else {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown notification progress type",
-                              ("Unknown notification progress type: %s ", progess_type.c_str()));
-  }
-
-  LOGGER(DEBUG) << "Progress " << progess_type << " = " << tmp_progress_value;
-
-  *progress_value = tmp_progress_value;
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetProgressValue(notification_h noti_handle,
-                                                    const std::string& progress_type,
-                                                    double progress_value, bool is_update) {
-  ScopeLogger();
-  int ret;
-
-  if (progress_type == kProgressTypeByte) {
-    ret = notification_set_size(noti_handle, progress_value);
-
-    if (is_update) {
-      ret = notification_update_size(noti_handle, NOTIFICATION_PRIV_ID_NONE, progress_value);
-    }
-  } else if (progress_type == kProgressTypePercentage) {
-    // native api uses range 0-1, but webapi expects 0-100, so we need to divide by 100
-    ret = notification_set_progress(noti_handle, progress_value / 100);
-
-    if (is_update) {
-      ret = notification_update_progress(noti_handle, NOTIFICATION_PRIV_ID_NONE, progress_value);
-    }
-  } else {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown notification progress type",
-                              ("Unknown notification progress type: %s ", progress_type.c_str()));
-  }
-
-  if (ret != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Set notification progress/size error",
-                              ("Set notification progress/size error: %d", ret));
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetPostedTime(notification_h noti_handle, time_t* posted_time) {
-  ScopeLogger();
-  *posted_time = 0;
-
-  if (notification_get_insert_time(noti_handle, posted_time) != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Get notification posted time error");
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetNotiHandle(int id, notification_h* noti_handle) {
-  ScopeLogger();
-  *noti_handle = notification_load(NULL, id);
-  if (NULL == *noti_handle) {
-    return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Not found or removed notification id");
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::GetAppControl(notification_h noti_handle,
-                                                 app_control_h* app_control) {
-  ScopeLogger();
-  int ret = notification_get_launch_option(noti_handle, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL,
-                                           static_cast<void*>(app_control));
-  if (ret != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Notification get launch option error",
-                              ("Notification get launch option error: %d", ret));
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::CreateAppControl(app_control_h* app_control) {
-  ScopeLogger();
-  int ret = app_control_create(app_control);
-  if (ret != APP_CONTROL_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Application create error",
-                              ("Application create error: %d", ret));
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-PlatformResult StatusNotification::SetAppControl(notification_h noti_handle,
-                                                 app_control_h app_control) {
-  ScopeLogger();
-  int ret = notification_set_launch_option(noti_handle, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL,
-                                           static_cast<void*>(app_control));
-  if (ret != APP_CONTROL_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Notification set launch option error",
-                              ("Notification set launch option error: %d", ret));
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
 PlatformResult StatusNotification::ToJson(int id, notification_h noti_handle,
                                           app_control_h app_handle, picojson::object* out_ptr) {
   ScopeLogger();
   picojson::object& out = *out_ptr;
 
-  out["id"] = picojson::value(std::to_string(id));
-  out["type"] = picojson::value("STATUS");
-
-  // Nitification type
-  notification_type_e noti_type = NOTIFICATION_TYPE_NONE;
-  int ret = notification_get_type(noti_handle, &noti_type);
-  if (ret != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Notification get type error",
-                              ("Notification get type error: %d", ret));
-  }
-
-  notification_ly_type_e noti_layout = NOTIFICATION_LY_NONE;
-  ret = notification_get_layout(noti_handle, &noti_layout);
-  if (ret != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Notification get layout error",
-                              ("Notification get layout error: %d", ret));
-  }
+  PlatformResult status = AddCommonMembersToJson(id, noti_handle, out_ptr);
+  CHECK_ERROR(status);
 
   std::string noti_type_str;
-  PlatformResult status = StatusTypeFromPlatform(noti_type, noti_layout, &noti_type_str);
-  if (status.IsError()) return status;
-  out["statusType"] = picojson::value(noti_type_str);
-
-  std::string value_str;
-  status = GetImage(noti_handle, NOTIFICATION_IMAGE_TYPE_ICON, &value_str);
-  if (status.IsError()) return status;
-  if (value_str.length()) {
-    out["iconPath"] =
-        picojson::value(common::FilesystemProvider::Create().GetVirtualPath(value_str));
-  }
-
-  status = GetImage(noti_handle, NOTIFICATION_IMAGE_TYPE_ICON_SUB, &value_str);
-  if (status.IsError()) return status;
-  if (value_str.length()) {
-    out["subIconPath"] =
-        picojson::value(common::FilesystemProvider::Create().GetVirtualPath(value_str));
-  }
-
-  long number;
-  status = GetNumber(noti_handle, NOTIFICATION_TEXT_TYPE_EVENT_COUNT, &number);
-  if (status.IsError()) return status;
-  if (number >= 0) {
-    out["number"] = picojson::value(static_cast<double>(number));
-  }
-
-  picojson::array detail_infos = picojson::array();
-  status = GetDetailInfos(noti_handle, &detail_infos);
-  if (status.IsError()) return status;
-  if (detail_infos.size()) {
-    out["detailInfo"] = picojson::value(detail_infos);
-  }
-
-  status = GetLedColor(noti_handle, &value_str);
-  if (status.IsError()) return status;
-  if (value_str.length()) {
-    out["ledColor"] = picojson::value(value_str);
-  }
-
-  unsigned long on_period;
-  unsigned long off_period;
-  status = GetLedPeriod(noti_handle, &on_period, &off_period);
-  if (status.IsError()) return status;
-  out["ledOnPeriod"] = picojson::value(static_cast<double>(on_period));
-  out["ledOffPeriod"] = picojson::value(static_cast<double>(off_period));
+  status = AddTypeToJson(noti_handle, "statusType", out_ptr, &noti_type_str);
+  CHECK_ERROR(status);
 
-  status = GetImage(noti_handle, NOTIFICATION_IMAGE_TYPE_BACKGROUND, &value_str);
-  if (status.IsError()) return status;
-  if (value_str.length()) {
-    out["backgroundImagePath"] =
-        picojson::value(common::FilesystemProvider::Create().GetVirtualPath(value_str));
-  }
+  // iconPath
+  status = AddPathToJson(noti_handle, NOTIFICATION_IMAGE_TYPE_ICON, "iconPath", out_ptr);
+  CHECK_ERROR(status);
 
-  picojson::array thumbnails = picojson::array();
-  status = GetThumbnails(noti_handle, &thumbnails);
-  if (status.IsError()) return status;
-  if (thumbnails.size()) {
-    out["thumbnails"] = picojson::value(thumbnails);
-  }
+  // subIconPath
+  status = AddPathToJson(noti_handle, NOTIFICATION_IMAGE_TYPE_ICON_SUB, "subIconPath", out_ptr);
+  CHECK_ERROR(status);
 
-  status = GetSoundPath(noti_handle, &value_str);
-  if (status.IsError()) return status;
-  if (value_str.length()) {
-    out["soundPath"] =
-        picojson::value(common::FilesystemProvider::Create().GetVirtualPath(value_str));
-  }
+  // eventsNumber
+  status = AddEventsNumberToJson(noti_handle, "number", &out);
+  CHECK_ERROR(status);
 
-  bool vibration;
-  status = GetVibration(noti_handle, &vibration);
-  if (status.IsError()) return status;
-  out["vibration"] = picojson::value(vibration);
+  // detailInfo
+  status = AddDetailInfosToJson(noti_handle, &out);
+  CHECK_ERROR(status);
 
-  picojson::object app_control = picojson::object();
-  status = GetApplicationControl(app_handle, &app_control);
-  if (status.IsError()) return status;
-  if (app_control.size()) {
-    out["appControl"] = picojson::value(app_control);
-  }
+  // ledColor
+  status = AddLedColorToJson(noti_handle, &out);
+  CHECK_ERROR(status);
 
-  status = GetApplicationId(app_handle, &value_str);
-  if (status.IsError()) return status;
-  if (value_str.length()) {
-    out["appId"] = picojson::value(value_str);
-  }
+  // ledOnPeriod, ledOffPeriod
+  status = AddLedOnOffPeriodToJson(noti_handle, &out);
+  CHECK_ERROR(status);
 
-  std::string progress_type;
-  status = GetImage(noti_handle, NOTIFICATION_IMAGE_TYPE_LIST_5, &progress_type);
-  if (status.IsError()) return status;
+  // backgroundImagePath
+  status = AddPathToJson(noti_handle, NOTIFICATION_IMAGE_TYPE_BACKGROUND, "backgroundImagePath",
+                         out_ptr);
+  CHECK_ERROR(status);
 
-  // push service daemon doesn't set progress type
-  // so use default if notification type is different from "PROGRESS"
-  if ("PROGRESS" != noti_type_str) {
-    progress_type = progress_type == kProgressTypeByte ? progress_type : kProgressTypePercentage;
-  }
-  out["progressType"] = picojson::value(progress_type);
+  // thumbnails
+  status = AddPathsArrayToJson(noti_handle, thumbnails_map_, "thumbnails", out_ptr);
+  CHECK_ERROR(status);
 
-  double progress_value;
-  status = GetProgressValue(noti_handle, progress_type, &progress_value);
-  if (status.IsError()) return status;
-  out["progressValue"] = picojson::value(progress_value);
+  // soundPath
+  status = AddSoundPathToJson(noti_handle, &out);
+  CHECK_ERROR(status);
 
-  time_t posted_time;
-  status = GetPostedTime(noti_handle, &posted_time);
-  if (status.IsError()) return status;
-  out["postedTime"] = picojson::value(static_cast<double>(posted_time) * 1000.0);
+  // vibration
+  status = AddVibrationToJson(noti_handle, &out);
+  CHECK_ERROR(status);
 
-  status = GetText(noti_handle, NOTIFICATION_TEXT_TYPE_TITLE, &value_str);
-  if (status.IsError()) return status;
-  out["title"] = picojson::value(value_str);
+  // appControl, appId
+  status = AddAppControlInfoToJson(noti_handle, app_handle, &out);
+  CHECK_ERROR(status);
 
-  status = GetText(noti_handle, NOTIFICATION_TEXT_TYPE_CONTENT, &value_str);
-  if (status.IsError()) return status;
-  if (value_str.length()) {
-    out["content"] = picojson::value(value_str);
-  }
+  // progressType, progressValue
+  status = AddProgressTypeAndValueToJson(noti_handle, noti_type_str, &out);
+  CHECK_ERROR(status);
 
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
-PlatformResult StatusNotification::FromJson(const picojson::object& args, bool is_update,
-                                            picojson::object* out_ptr) {
+PlatformResult StatusNotification::GetNotiHandleFromJson(const picojson::value& noti_val,
+                                                         bool is_update,
+                                                         notification_h* noti_handle) {
   ScopeLogger();
-  picojson::object noti_obj = common::FromJson<picojson::object>(args, "notification");
-
-  const std::string& status_type = common::FromJson<std::string>(noti_obj, "statusType");
-
-  notification_type_e noti_type;
-  PlatformResult status = StatusTypeToPlatform(status_type, &noti_type);
-  if (status.IsError()) return status;
-
-  int id = NOTIFICATION_PRIV_ID_NONE;
-  int ret;
-
-  notification_h noti_handle = nullptr;
-  app_control_h app_control = NULL;
-
-  SCOPE_EXIT {
-    if (app_control) {
-      app_control_destroy(app_control);
-    }
-    notification_free(noti_handle);
-  };
-
-  if (is_update) {
-    id = std::stoi(common::FromJson<std::string>(noti_obj, "id"));
-
-    PlatformResult status = GetNotiHandle(id, &noti_handle);
-    if (status.IsError()) return status;
-
-  } else {
-    status = Create(noti_type, &noti_handle);
-    if (status.IsError()) return status;
-  }
-
-  status = SetLayout(noti_handle, status_type);
-  if (status.IsError()) {
-    return status;
-  }
+  picojson::object noti_obj = noti_val.get<picojson::object>();
 
-  picojson::value val(noti_obj);
-  if (val.contains("iconPath") && !IsNull(noti_obj, "iconPath")) {
-    const std::string& value_str = common::FromJson<std::string>(noti_obj, "iconPath");
-    std::string real_path = common::FilesystemProvider::Create().GetRealPath(value_str);
+  notification_h tmp_noti = nullptr;
+  // statusType, id
+  PlatformResult status = InitNotiFromJson(noti_obj, "statusType", is_update, &tmp_noti);
+  CHECK_ERROR(status);
+  std::unique_ptr<std::remove_pointer<notification_h>::type, int (*)(notification_h)> tmp_noti_ptr(
+      tmp_noti, &notification_free);  // automatically release the memory
 
-    status = SetImage(noti_handle, NOTIFICATION_IMAGE_TYPE_ICON, real_path);
-    if (status.IsError()) {
-      return status;
-    }
-  }
+  // title, content
+  status = SetCommonMembersFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
 
-  if (val.contains("subIconPath") && !IsNull(noti_obj, "subIconPath")) {
-    const std::string& value_str = common::FromJson<std::string>(noti_obj, "subIconPath");
-    std::string real_path = common::FilesystemProvider::Create().GetRealPath(value_str);
+  // iconPath
+  status = SetPathFromJson(noti_val, NOTIFICATION_IMAGE_TYPE_ICON, "iconPath", tmp_noti);
+  CHECK_ERROR(status);
 
-    status = SetImage(noti_handle, NOTIFICATION_IMAGE_TYPE_ICON_SUB, real_path);
-    if (status.IsError()) {
-      return status;
-    }
-  }
+  // subIconPath
+  status = SetPathFromJson(noti_val, NOTIFICATION_IMAGE_TYPE_ICON_SUB, "subIconPath", tmp_noti);
+  CHECK_ERROR(status);
 
-  if (val.contains("number") && !IsNull(noti_obj, "number")) {
-    long number = (long)common::FromJson<double>(noti_obj, "number");
-    status = SetText(noti_handle, NOTIFICATION_TEXT_TYPE_EVENT_COUNT, std::to_string(number));
-    if (status.IsError()) {
-      return status;
-    }
-  }
+  // number
+  status = SetEventsNumberFromJson(noti_val, "number", tmp_noti);
+  CHECK_ERROR(status);
 
-  if (val.contains("detailInfo") && !IsNull(noti_obj, "detailInfo")) {
-    status = SetDetailInfos(noti_handle, common::FromJson<picojson::array>(noti_obj, "detailInfo"));
-    if (status.IsError()) {
-      return status;
-    }
-  }
+  // detailInfo
+  status = SetDetailInfosFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
 
-  if (val.contains("ledColor") && !IsNull(noti_obj, "ledColor")) {
-    status = SetLedColor(noti_handle, common::FromJson<std::string>(noti_obj, "ledColor"));
-    if (status.IsError()) {
-      return status;
-    }
-  }
+  // ledColor
+  status = SetLedColorFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
 
-  status = SetLedOnPeriod(
-      noti_handle, static_cast<unsigned long>(common::FromJson<double>(noti_obj, "ledOnPeriod")));
-  if (status.IsError()) {
-    return status;
-  }
+  // ledOnPeriod
+  status = SetLedOnPeriodFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
 
-  status = SetLedOffPeriod(
-      noti_handle, static_cast<unsigned long>(common::FromJson<double>(noti_obj, "ledOffPeriod")));
-  if (status.IsError()) {
-    return status;
-  }
+  // ledOffPeriod
+  status = SetLedOffPeriodFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
 
-  if (val.contains("backgroundImagePath") && !IsNull(noti_obj, "backgroundImagePath")) {
-    const std::string& value_str = common::FromJson<std::string>(noti_obj, "backgroundImagePath");
-    std::string real_path = common::FilesystemProvider::Create().GetRealPath(value_str);
+  // backgroundImagePath
+  status = SetPathFromJson(noti_val, NOTIFICATION_IMAGE_TYPE_BACKGROUND, "backgroundImagePath",
+                           tmp_noti);
+  CHECK_ERROR(status);
 
-    status = SetImage(noti_handle, NOTIFICATION_IMAGE_TYPE_BACKGROUND, real_path);
-    if (status.IsError()) {
-      return status;
-    }
-  }
+  // thumbnails
+  status = SetPathsArrayFromJson(noti_val, thumbnails_map_, "thumbnails", tmp_noti);
+  CHECK_ERROR(status);
 
-  if (val.contains("thumbnails") && !IsNull(noti_obj, "thumbnails")) {
-    status = SetThumbnails(noti_handle, common::FromJson<picojson::array>(noti_obj, "thumbnails"));
-    if (status.IsError()) {
-      return status;
-    }
-  }
+  // soundPath
+  status = SetSoundPathFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
 
-  if (val.contains("soundPath") && !IsNull(noti_obj, "soundPath")) {
-    const std::string& value_str = common::FromJson<std::string>(noti_obj, "soundPath");
-    std::string real_path = common::FilesystemProvider::Create().GetRealPath(value_str);
+  // vibration
+  status = SetVibrationFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
 
-    status = SetSoundPath(noti_handle, real_path);
-    if (status.IsError()) {
-      return status;
-    }
-  }
+  // appControl, appId
+  status = SetAppControlInfoFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
 
-  status = SetVibration(noti_handle, common::FromJson<bool>(noti_obj, "vibration"));
-  if (status.IsError()) {
-    return status;
-  }
+  // progressType, progressValue
+  status = SetProgressTypeAndValueFromJson(noti_val, is_update, tmp_noti);
+  CHECK_ERROR(status);
 
-  status = CreateAppControl(&app_control);
-  if (status.IsError()) {
-    return status;
-  }
-
-  if (val.contains("appControl") && !IsNull(noti_obj, "appControl")) {
-    status = SetApplicationControl(app_control,
-                                   common::FromJson<picojson::object>(noti_obj, "appControl"));
-    if (status.IsError()) {
-      return status;
-    }
-  }
-
-  if (val.contains("appId") && !IsNull(noti_obj, "appId")) {
-    status = SetApplicationId(app_control, common::FromJson<std::string>(noti_obj, "appId"));
-    if (status.IsError()) {
-      return status;
-    }
-  }
-
-  const std::string& progress_type = common::FromJson<std::string>(noti_obj, "progressType");
-  status = SetImage(noti_handle, NOTIFICATION_IMAGE_TYPE_LIST_5, progress_type);
-  if (status.IsError()) {
-    return status;
-  }
-
-  double progressValue;
-  if (val.contains("progressValue") && !IsNull(noti_obj, "progressValue")) {
-    progressValue = common::FromJson<double>(noti_obj, "progressValue");
-  } else {
-    progressValue = -1;
-  }
-
-  status = SetProgressValue(noti_handle, progress_type, progressValue, is_update);
-
-  if (status.IsError()) {
-    return status;
-  }
-
-  status = SetText(noti_handle, NOTIFICATION_TEXT_TYPE_TITLE,
-                   common::FromJson<std::string>(noti_obj, "title"));
-  if (status.IsError()) {
-    return status;
-  }
-
-  if (val.contains("content") && !IsNull(noti_obj, "content")) {
-    status = SetText(noti_handle, NOTIFICATION_TEXT_TYPE_CONTENT,
-                     common::FromJson<std::string>(noti_obj, "content"));
-    if (status.IsError()) {
-      return status;
-    }
-  }
-
-  status = SetAppControl(noti_handle, app_control);
-
-  if (is_update) {
-    ret = notification_update(noti_handle);
-
-  } else {
-    ret = notification_insert(noti_handle, &id);
-    if (NOTIFICATION_ERROR_NONE != ret) {
-      return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Cannot insert notification");
-    }
-  }
-  if (ret != NOTIFICATION_ERROR_NONE) {
-    return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Post/Update notification error",
-                              ("Post/Update notification error: %d", ret));
-  }
-
-  time_t posted_time;
-  status = GetPostedTime(noti_handle, &posted_time);
-  if (status.IsError()) {
-    return status;
-  }
-
-  if (is_update) {
-    return PlatformResult(ErrorCode::NO_ERROR);
-  }
-
-  picojson::object& out = *out_ptr;
-  out["id"] = picojson::value(std::to_string(id));
-  out["postedTime"] = picojson::value(static_cast<double>(posted_time) * 1000.0);
-  out["type"] = picojson::value("STATUS");
+  *noti_handle = tmp_noti_ptr.release();
 
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
+PlatformResult StatusNotification::PostStatusNotification(const picojson::object& args,
+                                                          bool is_update,
+                                                          picojson::object* out_ptr) {
+  ScopeLogger();
+  return PostNotification(args, is_update, out_ptr, GetNotiHandleFromJson);
+}
+
 }  // namespace notification
 }  // namespace extension
index c86784e..2c50675 100644 (file)
 #include "common/picojson.h"
 #include "common/platform_result.h"
 
+#include "common/XW_Extension.h"
+
+#include "notification/common_notification.h"
+
 namespace extension {
 namespace notification {
 
-typedef std::map<int, notification_text_type_e> InformationEnumMap;
-typedef std::map<int, notification_image_type_e> ImageEnumMap;
-
-class StatusNotification {
+class StatusNotification : public CommonNotification {
  public:
-  static common::PlatformResult ToJson(int id, notification_h noti_handle, app_control_h app_handle,
-                                       picojson::object* out_ptr);
-  static common::PlatformResult FromJson(const picojson::object& args, bool is_update,
-                                         picojson::object* out_ptr);
-  static common::PlatformResult GetAppControl(notification_h noti_handle,
-                                              app_control_h* app_control);
-  static common::PlatformResult GetNotiHandle(int id, notification_h* noti_handle);
+  XW_EXPORT static common::PlatformResult ToJson(int id, notification_h noti_handle,
+                                                 app_control_h app_handle,
+                                                 picojson::object* out_ptr);
+  XW_EXPORT static common::PlatformResult GetNotiHandleFromJson(const picojson::value& noti_val,
+                                                                bool is_update,
+                                                                notification_h* noti_handle);
+  static common::PlatformResult PostStatusNotification(const picojson::object& args, bool is_update,
+                                                       picojson::object* out_ptr);
 
  private:
   StatusNotification();
   virtual ~StatusNotification();
-
-  static const InformationEnumMap info_map_;
-  static const InformationEnumMap info_sub_map_;
-  static const ImageEnumMap thumbnails_map_;
-
-  static common::PlatformResult StatusTypeFromPlatform(notification_type_e noti_type,
-                                                       notification_ly_type_e noti_layout,
-                                                       std::string* type);
-  static common::PlatformResult StatusTypeToPlatform(const std::string& type,
-                                                     notification_type_e* noti_type);
-  static common::PlatformResult Create(notification_type_e noti_type, notification_h* noti_handle);
-  static common::PlatformResult GetImage(notification_h noti_handle,
-                                         notification_image_type_e image_type,
-                                         std::string* image_path);
-  static common::PlatformResult SetImage(notification_h noti_handle,
-                                         notification_image_type_e image_type,
-                                         const std::string& image_path);
-  static common::PlatformResult GetText(notification_h noti_handle,
-                                        notification_text_type_e text_type, std::string* noti_text);
-  static common::PlatformResult SetText(notification_h noti_handle,
-                                        notification_text_type_e text_type,
-                                        const std::string& noti_text);
-  static common::PlatformResult GetNumber(notification_h noti_handle,
-                                          notification_text_type_e text_type, long* number);
-  static common::PlatformResult GetDetailInfos(notification_h noti_handle, picojson::array* out);
-  static common::PlatformResult SetDetailInfos(notification_h noti_handle,
-                                               const picojson::array& value);
-  static common::PlatformResult GetLedColor(notification_h noti_handle, std::string* led_color);
-  static common::PlatformResult SetLedColor(notification_h noti_handle,
-                                            const std::string& led_color);
-  static common::PlatformResult GetLedPeriod(notification_h noti_handle, unsigned long* on_period,
-                                             unsigned long* off_period);
-  static common::PlatformResult SetLedOnPeriod(notification_h noti_handle, unsigned long on_period);
-  static common::PlatformResult SetLedOffPeriod(notification_h noti_handle,
-                                                unsigned long off_period);
-  static common::PlatformResult GetThumbnails(notification_h noti_handle, picojson::array* out);
-  static common::PlatformResult SetThumbnails(notification_h noti_handle,
-                                              const picojson::array& value);
-  static common::PlatformResult GetSoundPath(notification_h noti_handle, std::string* sound_path);
-  static common::PlatformResult SetSoundPath(notification_h noti_handle,
-                                             const std::string& sound_path);
-  static common::PlatformResult GetVibration(notification_h noti_handle, bool* vibration);
-  static common::PlatformResult SetVibration(notification_h noti_handle, bool vibration);
-  static common::PlatformResult GetApplicationControl(app_control_h app_handle,
-                                                      picojson::object* out_ptr);
-  static common::PlatformResult SetApplicationControl(app_control_h app_handle,
-                                                      const picojson::object& app_ctrl);
-  static common::PlatformResult GetApplicationId(app_control_h app_handle, std::string* app_id);
-  static common::PlatformResult SetApplicationId(app_control_h app_handle,
-                                                 const std::string& app_id);
-  static common::PlatformResult GetProgressValue(notification_h noti_handle,
-                                                 const std::string& progess_type,
-                                                 double* progress_value);
-  static common::PlatformResult SetProgressValue(notification_h noti_handle,
-                                                 const std::string& progress_type,
-                                                 double progress_value, bool is_update);
-  static common::PlatformResult GetPostedTime(notification_h noti_handle, time_t* posted_time);
-  static common::PlatformResult SetLayout(notification_h noti_handle, const std::string& noti_type);
-  static common::PlatformResult SetAppControl(notification_h noti_handle,
-                                              app_control_h app_control);
-  static common::PlatformResult CreateAppControl(app_control_h* app_control);
-
-  static bool IsColorFormatNumberic(const std::string& color);
 };
 
 }  // namespace notification
diff --git a/src/notification/user_notification.cc b/src/notification/user_notification.cc
new file mode 100644 (file)
index 0000000..d7960de
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2017 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 "notification/user_notification.h"
+
+#include "common/converter.h"
+#include "common/logger.h"
+#include "common/scope_exit.h"
+
+namespace extension {
+namespace notification {
+
+using namespace common;
+
+UserNotification::UserNotification() {
+}
+
+UserNotification::~UserNotification() {
+}
+
+PlatformResult UserNotification::ToJson(int id, notification_h noti_handle,
+                                        app_control_h app_handle, picojson::object* out_ptr) {
+  ScopeLogger();
+  PlatformResult ret = AddCommonMembersToJson(id, noti_handle, out_ptr);
+  CHECK_ERROR(ret);
+
+  std::string noti_type_str;
+  ret = AddTypeToJson(noti_handle, "userType", out_ptr, &noti_type_str);
+  CHECK_ERROR(ret);
+
+  ret = AddTextContentsToJson(noti_handle, noti_type_str, out_ptr);
+  CHECK_ERROR(ret);
+
+  ret = AddImagesToJson(noti_handle, out_ptr);
+  CHECK_ERROR(ret);
+
+  ret = AddThumbnailsToJson(noti_handle, out_ptr);
+  CHECK_ERROR(ret);
+
+  ret = AddActionsToJson(noti_handle, app_handle, out_ptr);
+  CHECK_ERROR(ret);
+
+  ret = AddGroupContentsToJson(noti_handle, out_ptr);
+  CHECK_ERROR(ret);
+
+  ret = AddLedsToJson(noti_handle, out_ptr);
+  CHECK_ERROR(ret);
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::GetNotiHandleFromJson(const picojson::value& noti_val,
+                                                       bool is_update,
+                                                       notification_h* noti_handle) {
+  ScopeLogger();
+  picojson::object noti_obj = noti_val.get<picojson::object>();
+
+  notification_h tmp_noti = nullptr;
+  PlatformResult status = InitNotiFromJson(noti_obj, "userType", is_update, &tmp_noti);
+  CHECK_ERROR(status);
+  std::unique_ptr<std::remove_pointer<notification_h>::type, int (*)(notification_h)> tmp_noti_ptr(
+      tmp_noti, &notification_free);  // automatically release the memory
+
+  status = SetCommonMembersFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
+
+  status = SetTextContentsFromJson(noti_val, is_update, tmp_noti);
+  CHECK_ERROR(status);
+
+  status = SetImagesFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
+
+  status = SetThumbnailsFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
+
+  status = SetActionsFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
+
+  status = SetGroupContentsFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
+
+  status = SetLedsFromJson(noti_val, tmp_noti);
+  CHECK_ERROR(status);
+
+  *noti_handle = tmp_noti_ptr.release();
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::PostUserNotification(const picojson::object& args, bool is_update,
+                                                      picojson::object* out_ptr) {
+  ScopeLogger();
+  return PostNotification(args, is_update, out_ptr, GetNotiHandleFromJson);
+}
+
+PlatformResult UserNotification::AddTextContentsToJson(notification_h noti_handle,
+                                                       std::string noti_type_str,
+                                                       picojson::object* out_ptr) {
+  ScopeLogger();
+
+  picojson::value text_contents = picojson::value(picojson::object());
+  picojson::object& text_contents_obj = text_contents.get<picojson::object>();
+
+  // progressType, progressValue
+  PlatformResult status =
+      AddProgressTypeAndValueToJson(noti_handle, noti_type_str, &text_contents_obj);
+  CHECK_ERROR(status);
+
+  // eventsNumber
+  status = AddEventsNumberToJson(noti_handle, "eventsNumber", &text_contents_obj);
+  CHECK_ERROR(status);
+
+  // detailInfo
+  status = AddDetailInfosToJson(noti_handle, &text_contents_obj);
+  CHECK_ERROR(status);
+
+  // buttonsTexts
+  status = AddTextsArrayToJson(noti_handle, buttons_texts_map_, "buttonsTexts", &text_contents_obj);
+  CHECK_ERROR(status);
+
+  // contentForOff
+  status = AddTextToJson(noti_handle, NOTIFICATION_TEXT_TYPE_CONTENT_FOR_DISPLAY_OPTION_IS_OFF,
+                         "contentForOff", &text_contents_obj);
+  CHECK_ERROR(status);
+
+  (*out_ptr)["textContents"] = text_contents;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::AddImagesToJson(notification_h noti_handle,
+                                                 picojson::object* out_ptr) {
+  ScopeLogger();
+
+  picojson::value images_contents = picojson::value(picojson::object());
+  picojson::object& images_contents_obj = images_contents.get<picojson::object>();
+
+  // iconPath
+  PlatformResult status =
+      AddPathToJson(noti_handle, NOTIFICATION_IMAGE_TYPE_ICON, "iconPath", &images_contents_obj);
+  CHECK_ERROR(status);
+
+  // subIconPath
+  status = AddPathToJson(noti_handle, NOTIFICATION_IMAGE_TYPE_ICON_SUB, "subIconPath",
+                         &images_contents_obj);
+  CHECK_ERROR(status);
+
+  // indicatorIconPath
+  status = AddPathToJson(noti_handle, NOTIFICATION_IMAGE_TYPE_ICON_FOR_INDICATOR,
+                         "indicatorIconPath", &images_contents_obj);
+  CHECK_ERROR(status);
+
+  // lockScreenIconPath
+  status = AddPathToJson(noti_handle, NOTIFICATION_IMAGE_TYPE_ICON_FOR_LOCK, "lockScreenIconPath",
+                         &images_contents_obj);
+  CHECK_ERROR(status);
+
+  // buttonIconPaths
+  status = AddPathsArrayToJson(noti_handle, buttons_icon_paths_map_, "buttonIconPaths",
+                               &images_contents_obj);
+  CHECK_ERROR(status);
+
+  // backgroundImagePath
+  status = AddPathToJson(noti_handle, NOTIFICATION_IMAGE_TYPE_BACKGROUND, "backgroundImagePath",
+                         &images_contents_obj);
+  CHECK_ERROR(status);
+
+  (*out_ptr)["images"] = images_contents;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::AddThumbnailsToJson(notification_h noti_handle,
+                                                     picojson::object* out_ptr) {
+  ScopeLogger();
+
+  picojson::value thumbnails_contents = picojson::value(picojson::object());
+  picojson::object& thumbnails_contents_obj = thumbnails_contents.get<picojson::object>();
+
+  // lockScreenThumbnailIconPath
+  PlatformResult status = AddPathToJson(noti_handle, NOTIFICATION_IMAGE_TYPE_THUMBNAIL_FOR_LOCK,
+                                        "lockScreenThumbnailIconPath", &thumbnails_contents_obj);
+  CHECK_ERROR(status);
+
+  // thumbnailIconPath
+  status = AddPathToJson(noti_handle, NOTIFICATION_IMAGE_TYPE_THUMBNAIL, "thumbnailIconPath",
+                         &thumbnails_contents_obj);
+  CHECK_ERROR(status);
+
+  // thumbnails
+  status =
+      AddPathsArrayToJson(noti_handle, thumbnails_map_, "thumbnails", &thumbnails_contents_obj);
+  CHECK_ERROR(status);
+
+  (*out_ptr)["thumbnails"] = thumbnails_contents;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::AddActionsToJson(notification_h noti_handle,
+                                                  app_control_h app_handle,
+                                                  picojson::object* out_ptr) {
+  ScopeLogger();
+
+  picojson::value actions_contents = picojson::value(picojson::object());
+  picojson::object& actions_contents_obj = actions_contents.get<picojson::object>();
+
+  // soundPath
+  PlatformResult status = AddSoundPathToJson(noti_handle, &actions_contents_obj);
+  CHECK_ERROR(status);
+
+  // vibration
+  status = AddVibrationToJson(noti_handle, &actions_contents_obj);
+  CHECK_ERROR(status);
+
+  // appControl, appId
+  status = AddAppControlInfoToJson(noti_handle, app_handle, &actions_contents_obj);
+  CHECK_ERROR(status);
+
+  (*out_ptr)["actions"] = actions_contents;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::AddGroupContentsToJson(notification_h noti_handle,
+                                                        picojson::object* out_ptr) {
+  ScopeLogger();
+
+  picojson::value group_contents = picojson::value(picojson::object());
+  picojson::object& group_contents_obj = group_contents.get<picojson::object>();
+
+  // groupTitle
+  PlatformResult status = AddTextToJson(noti_handle, NOTIFICATION_TEXT_TYPE_GROUP_TITLE,
+                                        "groupTitle", &group_contents_obj);
+  CHECK_ERROR(status);
+
+  // groupContent
+  status = AddTextToJson(noti_handle, NOTIFICATION_TEXT_TYPE_GROUP_CONTENT, "groupContent",
+                         &group_contents_obj);
+  CHECK_ERROR(status);
+
+  // groupContentForOff
+  status =
+      AddTextToJson(noti_handle, NOTIFICATION_TEXT_TYPE_GROUP_CONTENT_FOR_DISPLAY_OPTION_IS_OFF,
+                    "groupContentForOff", &group_contents_obj);
+  CHECK_ERROR(status);
+
+  (*out_ptr)["groupContents"] = group_contents;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::AddLedsToJson(notification_h noti_handle,
+                                               picojson::object* out_ptr) {
+  ScopeLogger();
+
+  picojson::value leds_contents = picojson::value(picojson::object());
+  picojson::object& leds_contents_obj = leds_contents.get<picojson::object>();
+
+  // ledColor
+  PlatformResult status = AddLedColorToJson(noti_handle, &leds_contents_obj);
+  CHECK_ERROR(status);
+
+  // ledOnPeriod, ledOffPeriod
+  status = AddLedOnOffPeriodToJson(noti_handle, &leds_contents_obj);
+  CHECK_ERROR(status);
+
+  (*out_ptr)["leds"] = leds_contents;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::SetTextContentsFromJson(const picojson::value& noti_value,
+                                                         bool is_update,
+                                                         notification_h noti_handle) {
+  ScopeLogger();
+  if (noti_value.contains("textContents") &&
+      noti_value.get("textContents").is<picojson::object>()) {
+    LoggerD("nullable member textContents is present - parsing it");
+    const picojson::value& text_contents_value = noti_value.get("textContents");
+
+    // progressType, progressValue
+    PlatformResult status =
+        SetProgressTypeAndValueFromJson(text_contents_value, is_update, noti_handle);
+    CHECK_ERROR(status);
+
+    // eventsNumber
+    status = SetEventsNumberFromJson(text_contents_value, "eventsNumber", noti_handle);
+    CHECK_ERROR(status);
+
+    // detailInfo
+    status = SetDetailInfosFromJson(text_contents_value, noti_handle);
+    CHECK_ERROR(status);
+
+    // buttonsTexts
+    status =
+        SetTextsArrayFromJson(text_contents_value, buttons_texts_map_, "buttonsTexts", noti_handle);
+    CHECK_ERROR(status);
+
+    // contentForOff
+    status = SetTextFromJson(text_contents_value,
+                             NOTIFICATION_TEXT_TYPE_CONTENT_FOR_DISPLAY_OPTION_IS_OFF,
+                             "contentForOff", noti_handle);
+    CHECK_ERROR(status);
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::SetImagesFromJson(const picojson::value& noti_value,
+                                                   notification_h noti_handle) {
+  ScopeLogger();
+  if (noti_value.contains("images") && noti_value.get("images").is<picojson::object>()) {
+    LoggerD("nullable member images is present - parsing it");
+    const picojson::value& images_value = noti_value.get("images");
+
+    // iconPath
+    PlatformResult status =
+        SetPathFromJson(images_value, NOTIFICATION_IMAGE_TYPE_ICON, "iconPath", noti_handle);
+    CHECK_ERROR(status);
+
+    // subIconPath
+    status =
+        SetPathFromJson(images_value, NOTIFICATION_IMAGE_TYPE_ICON_SUB, "subIconPath", noti_handle);
+    CHECK_ERROR(status);
+
+    // indicatorIconPath
+    status = SetPathFromJson(images_value, NOTIFICATION_IMAGE_TYPE_ICON_FOR_INDICATOR,
+                             "indicatorIconPath", noti_handle);
+    CHECK_ERROR(status);
+
+    // lockScreenIconPath
+    status = SetPathFromJson(images_value, NOTIFICATION_IMAGE_TYPE_ICON_FOR_LOCK,
+                             "lockScreenIconPath", noti_handle);
+    CHECK_ERROR(status);
+
+    // buttonIconPaths
+    status = SetPathsArrayFromJson(images_value, buttons_icon_paths_map_, "buttonIconPaths",
+                                   noti_handle);
+    CHECK_ERROR(status);
+
+    // backgroundImagePath
+    status = SetPathFromJson(images_value, NOTIFICATION_IMAGE_TYPE_BACKGROUND,
+                             "backgroundImagePath", noti_handle);
+    CHECK_ERROR(status);
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::SetThumbnailsFromJson(const picojson::value& noti_value,
+                                                       notification_h noti_handle) {
+  ScopeLogger();
+
+  if (noti_value.contains("thumbnails") && noti_value.get("thumbnails").is<picojson::object>()) {
+    LoggerD("nullable member thumbnails is present - parsing it");
+    const picojson::value& thumbnails_value = noti_value.get("thumbnails");
+
+    // lockScreenThumbnailIconPath
+    PlatformResult status =
+        SetPathFromJson(thumbnails_value, NOTIFICATION_IMAGE_TYPE_THUMBNAIL_FOR_LOCK,
+                        "lockScreenThumbnailIconPath", noti_handle);
+    CHECK_ERROR(status);
+
+    // thumbnailIconPath
+    status = SetPathFromJson(thumbnails_value, NOTIFICATION_IMAGE_TYPE_THUMBNAIL,
+                             "thumbnailIconPath", noti_handle);
+    CHECK_ERROR(status);
+
+    // thumbnails
+    status = SetPathsArrayFromJson(thumbnails_value, thumbnails_map_, "thumbnails", noti_handle);
+    CHECK_ERROR(status);
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::SetActionsFromJson(const picojson::value& noti_value,
+                                                    notification_h noti_handle) {
+  ScopeLogger();
+
+  if (noti_value.contains("actions") && noti_value.get("actions").is<picojson::object>()) {
+    LoggerD("nullable member actions is present - parsing it");
+    const picojson::value& actions_value = noti_value.get("actions");
+
+    // soundPath
+    PlatformResult status = SetSoundPathFromJson(actions_value, noti_handle);
+    CHECK_ERROR(status);
+
+    // vibration
+    status = SetVibrationFromJson(actions_value, noti_handle);
+    CHECK_ERROR(status);
+
+    // appControl, appId
+    status = SetAppControlInfoFromJson(actions_value, noti_handle);
+    CHECK_ERROR(status);
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::SetGroupContentsFromJson(const picojson::value& noti_value,
+                                                          notification_h noti_handle) {
+  ScopeLogger();
+
+  if (noti_value.contains("groupContents") &&
+      noti_value.get("groupContents").is<picojson::object>()) {
+    LoggerD("nullable member groupContents is present - parsing it");
+    const picojson::value& group_contents_value = noti_value.get("groupContents");
+
+    // groupTitle
+    PlatformResult status = SetTextFromJson(
+        group_contents_value, NOTIFICATION_TEXT_TYPE_GROUP_TITLE, "groupTitle", noti_handle);
+    CHECK_ERROR(status);
+
+    // groupContent
+    status = SetTextFromJson(group_contents_value, NOTIFICATION_TEXT_TYPE_GROUP_CONTENT,
+                             "groupContent", noti_handle);
+    CHECK_ERROR(status);
+
+    // groupContentForOff
+    status = SetTextFromJson(group_contents_value,
+                             NOTIFICATION_TEXT_TYPE_GROUP_CONTENT_FOR_DISPLAY_OPTION_IS_OFF,
+                             "groupContentForOff", noti_handle);
+    CHECK_ERROR(status);
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult UserNotification::SetLedsFromJson(const picojson::value& noti_value,
+                                                 notification_h noti_handle) {
+  ScopeLogger();
+
+  if (noti_value.contains("leds") && noti_value.get("leds").is<picojson::object>()) {
+    LoggerD("nullable member leds is present - parsing it");
+    const picojson::value& leds_value = noti_value.get("leds");
+
+    // ledColor
+    PlatformResult status = SetLedColorFromJson(leds_value, noti_handle);
+    CHECK_ERROR(status);
+
+    // ledOnPeriod
+    status = SetLedOnPeriodFromJson(leds_value, noti_handle);
+    CHECK_ERROR(status);
+
+    // ledOffPeriod
+    status = SetLedOffPeriodFromJson(leds_value, noti_handle);
+    CHECK_ERROR(status);
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+}  // namespace notification
+}  // namespace extension
diff --git a/src/notification/user_notification.h b/src/notification/user_notification.h
new file mode 100644 (file)
index 0000000..86f1c9c
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017 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 NOTIFICATION_USER_NOTIFICATION_H_
+#define NOTIFICATION_USER_NOTIFICATION_H_
+
+#include "notification/common_notification.h"
+
+namespace extension {
+namespace notification {
+
+class UserNotification : public CommonNotification {
+ public:
+  XW_EXPORT static common::PlatformResult ToJson(int id, notification_h noti_handle,
+                                                 app_control_h app_handle,
+                                                 picojson::object* out_ptr);
+  XW_EXPORT static common::PlatformResult GetNotiHandleFromJson(const picojson::value& noti_val,
+                                                                bool is_update,
+                                                                notification_h* noti_handle);
+  static common::PlatformResult PostUserNotification(const picojson::object& args, bool is_update,
+                                                     picojson::object* out_ptr);
+
+  static common::PlatformResult AddTextContentsToJson(notification_h noti_handle,
+                                                      std::string noti_type_str,
+                                                      picojson::object* out_ptr);
+  static common::PlatformResult AddImagesToJson(notification_h noti_handle,
+                                                picojson::object* out_ptr);
+  static common::PlatformResult AddThumbnailsToJson(notification_h noti_handle,
+                                                    picojson::object* out_ptr);
+  static common::PlatformResult AddActionsToJson(notification_h noti_handle,
+                                                 app_control_h app_handle,
+                                                 picojson::object* out_ptr);
+  static common::PlatformResult AddGroupContentsToJson(notification_h noti_handle,
+                                                       picojson::object* out_ptr);
+  static common::PlatformResult AddLedsToJson(notification_h noti_handle,
+                                              picojson::object* out_ptr);
+
+  static common::PlatformResult SetTextContentsFromJson(const picojson::value& noti_val,
+                                                        bool is_update, notification_h noti_handle);
+  static common::PlatformResult SetImagesFromJson(const picojson::value& noti_val,
+                                                  notification_h noti_handle);
+  static common::PlatformResult SetThumbnailsFromJson(const picojson::value& noti_val,
+                                                      notification_h noti_handle);
+  static common::PlatformResult SetActionsFromJson(const picojson::value& noti_val,
+                                                   notification_h noti_handle);
+  static common::PlatformResult SetGroupContentsFromJson(const picojson::value& noti_val,
+                                                         notification_h noti_handle);
+  static common::PlatformResult SetLedsFromJson(const picojson::value& noti_val,
+                                                notification_h noti_handle);
+
+ private:
+  UserNotification();
+  virtual ~UserNotification();
+};
+
+}  // namespace notification
+}  // namespace extension
+
+#endif /* NOTIFICATION_USER_NOTIFICATION_H_ */
index 74a4204..37888ff 100755 (executable)
@@ -23,7 +23,6 @@
           'variables': {
             'packages': [
               'capi-system-device',
-              'deviced',
             ]
           },
         }],
index 3646d8f..4973b0c 100644 (file)
@@ -113,7 +113,7 @@ void PowerManager::ScreenStateChangeCB(device_callback_e type, void* value, void
     return;
   }
 
-  display_state_e state = static_cast<display_state_e>(reinterpret_cast<int>(value));
+  display_state_e state = static_cast<display_state_e>(reinterpret_cast<intptr_t>(value));
   if (manager->current_screen_state == state) {
     return;
   }
diff --git a/src/ppm/ppm.gyp b/src/ppm/ppm.gyp
new file mode 100644 (file)
index 0000000..6af4ad1
--- /dev/null
@@ -0,0 +1,30 @@
+{
+  'includes':[
+    '../common/common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'tizen_ppm',
+      'type': 'loadable_module',
+      'dependencies': [
+        '../common/common.gyp:tizen_common',
+      ],
+      'sources': [
+        'ppm_api.js',
+        'ppm_extension.cc',
+        'ppm_extension.h',
+        'ppm_instance.cc',
+        'ppm_instance.h',
+      ],
+      'conditions': [
+        ['tizen == 1', {
+          'variables': {
+            'packages': [
+              'capi-privacy-privilege-manager'
+            ]
+          },
+        }],
+      ],
+    },
+  ],
+}
diff --git a/src/ppm/ppm_api.js b/src/ppm/ppm_api.js
new file mode 100644 (file)
index 0000000..e6fa82a
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+var validator_ = xwalk.utils.validator;
+var type_ = xwalk.utils.type;
+var types_ = validator_.Types;
+var native_ = new xwalk.utils.NativeManager(extension);
+
+function PPMManager() {}
+
+PPMManager.prototype.checkPermission = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'privilege', type: types_.STRING }
+    ]);
+
+    var callArgs = {
+        privilege: args.privilege
+    };
+
+    var result = native_.callSync('PPMManager_checkPermission', callArgs);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+
+    return native_.getResultObject(result);
+};
+
+PPMManager.prototype.requestPermission = function() {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'privilege', type: 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 {
+            args.successCallback(result.result, result.privilege);
+        }
+    };
+
+    var callArgs = {
+        privilege: args.privilege
+    };
+
+    var result = native_.call('PPMManager_requestPermission', callArgs, callback);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+};
+
+// Exports
+exports = new PPMManager();
diff --git a/src/ppm/ppm_extension.cc b/src/ppm/ppm_extension.cc
new file mode 100644 (file)
index 0000000..c1d098b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 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 "ppm/ppm_extension.h"
+
+#include "ppm/ppm_instance.h"
+
+// This will be generated from ppm_api.js
+extern const char kSource_ppm_api[];
+
+common::Extension* CreateExtension() {
+  return new PPMExtension;
+}
+
+PPMExtension::PPMExtension() {
+  SetExtensionName("tizen.ppm");
+  SetJavaScriptAPI(kSource_ppm_api);
+}
+
+PPMExtension::~PPMExtension() {
+}
+
+common::Instance* PPMExtension::CreateInstance() {
+  return new extension::ppm::PPMInstance;
+}
diff --git a/src/ppm/ppm_extension.h b/src/ppm/ppm_extension.h
new file mode 100644 (file)
index 0000000..8df16c6
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 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 PPM_PPM_EXTENSION_H_
+#define PPM_PPM_EXTENSION_H_
+
+#include "common/extension.h"
+
+class PPMExtension : public common::Extension {
+ public:
+  PPMExtension();
+  virtual ~PPMExtension();
+
+ private:
+  virtual common::Instance* CreateInstance();
+};
+
+#endif  // PPM_PPM_EXTENSION_H_
diff --git a/src/ppm/ppm_instance.cc b/src/ppm/ppm_instance.cc
new file mode 100644 (file)
index 0000000..7f419a3
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017 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 "ppm/ppm_instance.h"
+
+#include <memory>
+
+#include "common/logger.h"
+#include "common/picojson.h"
+
+namespace extension {
+namespace ppm {
+
+namespace {
+const std::string kPPMCheckResultAllow = "PPM_ALLOW";
+const std::string kPPMCheckResultDeny = "PPM_DENY";
+const std::string kPPMCheckResultAsk = "PPM_ASK";
+const std::string kPPMCheckRequestResultAllowForever = "PPM_ALLOW_FOREVER";
+const std::string kPPMCheckRequestResultDenyForever = "PPM_DENY_FOREVER";
+const std::string kPPMCheckRequestResultDenyOnce = "PPM_DENY_ONCE";
+}
+
+struct ResponseCallbackData {
+  PPMInstance* _instance;
+  double callbackId;
+};
+
+PPMInstance::PPMInstance() {
+  ScopeLogger();
+  using std::placeholders::_1;
+  using std::placeholders::_2;
+
+#define REGISTER(c, x) RegisterSyncHandler(c, std::bind(&PPMInstance::x, this, _1, _2));
+
+  REGISTER("PPMManager_checkPermission", checkPermission);
+  REGISTER("PPMManager_requestPermission", requestPermission);
+
+#undef REGISTER
+}
+
+PPMInstance::~PPMInstance() {
+  ScopeLogger();
+}
+
+common::PlatformResult PPMInstance::convertError(int err, const std::string& message) {
+  ScopeLogger();
+
+  char* error = nullptr;
+  if (message.empty()) {
+    error = get_error_message(err);
+  } else {
+    error = (char*)message.c_str();
+  }
+
+  switch (err) {
+    case PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER:
+      return common::PlatformResult(common::ErrorCode::INVALID_VALUES_ERR, error);
+    case PRIVACY_PRIVILEGE_MANAGER_ERROR_IO_ERROR:
+    case PRIVACY_PRIVILEGE_MANAGER_ERROR_ALREADY_IN_PROGRESS:
+    case PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY:
+    case PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN:
+      return common::PlatformResult(common::ErrorCode::ABORT_ERR, error);
+    default:
+      return common::PlatformResult(common::ErrorCode::ABORT_ERR, "Abort error.");
+  }
+}
+
+std::string PPMInstance::CheckResultToString(ppm_check_result_e result) {
+  ScopeLogger();
+
+  switch (result) {
+    case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ALLOW:
+      return kPPMCheckResultAllow;
+    case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ASK:
+      return kPPMCheckResultAsk;
+    case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_DENY:
+    default:
+      return kPPMCheckResultDeny;
+  }
+}
+
+std::string PPMInstance::CheckRequestResultToString(ppm_request_result_e result) {
+  ScopeLogger();
+
+  switch (result) {
+    case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_ALLOW_FOREVER:
+      return kPPMCheckRequestResultAllowForever;
+    case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_DENY_FOREVER:
+      return kPPMCheckRequestResultDenyForever;
+    case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_DENY_ONCE:
+    default:
+      return kPPMCheckRequestResultDenyOnce;
+  }
+}
+
+void PPMInstance::ResponseCallback(ppm_call_cause_e cause, ppm_request_result_e result,
+                                   const char* privilege, 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.insert(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)));
+  } 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>();
+  LoggerD("Checking privilege: %s ", privilege.c_str());
+
+  ppm_check_result_e result = PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_DENY;
+
+  int ret = ppm_check_permission(privilege.c_str(), &result);
+
+  if (PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE != ret) {
+    LogAndReportError(convertError(ret), &out,
+                      ("checkPermission error: %d (%s)", ret, get_error_message(ret)));
+    return;
+  }
+
+  ReportSuccess(picojson::value(CheckResultToString(result)), out);
+}
+
+void PPMInstance::requestPermission(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  const double callback_id = args.get("callbackId").get<double>();
+
+  const std::string& privilege = args.get("privilege").get<std::string>();
+  LoggerD("Requesting privilege: %s ", privilege.c_str());
+
+  ResponseCallbackData* user_data{new ResponseCallbackData()};
+  user_data->_instance = this;
+  user_data->callbackId = callback_id;
+
+  int ret =
+      ppm_request_permission(privilege.c_str(), ResponseCallback, static_cast<void*>(user_data));
+
+  if (PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE != ret) {
+    LogAndReportError(convertError(ret), &out,
+                      ("checkPermission error: %d (%s)", ret, get_error_message(ret)));
+    return;
+  }
+
+  ReportSuccess(out);
+}
+
+}  // namespace ppm
+}  // namespace extension
diff --git a/src/ppm/ppm_instance.h b/src/ppm/ppm_instance.h
new file mode 100644 (file)
index 0000000..9d1825c
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 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 PPM_PPM_INSTANCE_H_
+#define PPM_PPM_INSTANCE_H_
+
+#include <string>
+
+#include "common/extension.h"
+#include "common/platform_exception.h"
+#include "common/platform_result.h"
+
+#include <privacy_privilege_manager.h>
+
+namespace extension {
+namespace ppm {
+
+class PPMInstance : public common::ParsedInstance {
+ public:
+  PPMInstance();
+  virtual ~PPMInstance();
+
+ private:
+  void checkPermission(const picojson::value& args, picojson::object& out);
+  void requestPermission(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);
+};
+
+}  // namespace ppm
+}  // namespace extension
+
+#endif  // PPM_PPM_INSTANCE_H_
index 0b5161b..eedd0f4 100644 (file)
@@ -22,7 +22,7 @@
         ['tizen == 1', {
           'variables': {
             'packages': [
-              'capi-appfw-application',
+              'capi-appfw-preference',
             ]
           },
         }],
index 5cdb2ad..6028465 100644 (file)
@@ -28,7 +28,7 @@
           'variables': {
             'packages': [
               'push',
-              'capi-appfw-application',
+              'capi-appfw-app-control',
               'libpcrecpp',
             ]
           },
index e33cd4c..2e9ea1e 100644 (file)
@@ -353,7 +353,7 @@ FMRadioManager::~FMRadioManager() {
 }
 
 PlatformResult FMRadioManager::Start(double frequency) {
-  ScopeLogger("freq: %d", frequency);
+  ScopeLogger("freq: %lf", frequency);
 
   radio_state_e state;
   const auto err = radio_get_state(radio_instance_, &state);
index 17d280a..9305c4f 100755 (executable)
@@ -33,7 +33,10 @@ var SensorType = {
     GRAVITY: 'GRAVITY',
     GYROSCOPE: 'GYROSCOPE',
     GYROSCOPE_ROTATION_VECTOR: 'GYROSCOPE_ROTATION_VECTOR',
-    LINEAR_ACCELERATION: 'LINEAR_ACCELERATION'
+    LINEAR_ACCELERATION: 'LINEAR_ACCELERATION',
+    MAGNETIC_UNCALIBRATED: 'MAGNETIC_UNCALIBRATED',
+    GYROSCOPE_UNCALIBRATED: 'GYROSCOPE_UNCALIBRATED',
+    ACCELERATION: 'ACCELERATION'
 };
 
 var ProximityState = {
@@ -99,9 +102,7 @@ SensorListener.prototype.start = function(successCallback, errorCallback) {
 
 SensorListener.prototype.stop = function() {
     if (SensorStates.NOT_STARTED != this.state) {
-        var result = native_.callSync('Sensor_stop', {
-            sensorType: this.sensorType
-        });
+        var result = native_.callSync('Sensor_stop', { sensorType: this.sensorType });
         if (native_.isFailure(result)) {
             throw native_.getErrorObject(result);
         }
@@ -182,7 +183,10 @@ var _sensorListeners = {
     GRAVITY: {},
     GYROSCOPE: {},
     GYROSCOPE_ROTATION_VECTOR: {},
-    LINEAR_ACCELERATION: {}
+    LINEAR_ACCELERATION: {},
+    MAGNETIC_UNCALIBRATED: {},
+    GYROSCOPE_UNCALIBRATED: {},
+    ACCELERATION: {}
 };
 
 var errorWrapper = function(err) {
@@ -251,6 +255,12 @@ function getDefaultSensor() {
         return new GyroscopeRotationVectorSensor();
     } else if (_supportedSensors[index] === SensorType.LINEAR_ACCELERATION) {
         return new LinearAccelerationSensor();
+    } else if (_supportedSensors[index] === SensorType.MAGNETIC_UNCALIBRATED) {
+        return new MagneticUncalibratedSensor();
+    } else if (_supportedSensors[index] === SensorType.GYROSCOPE_UNCALIBRATED) {
+        return new GyroscopeUncalibratedSensor();
+    } else if (_supportedSensors[index] === SensorType.ACCELERATION) {
+        return new AccelerationSensor();
     }
 }
 
@@ -266,7 +276,7 @@ SensorService.prototype.getAvailableSensors = function() {
     return _supportedSensors.slice();
 };
 
-//////////////////////Sensor classes//////////////////////
+//////////////////////Sensor classes/////////////////////////////
 //// Base Sensor class
 var Sensor = function(type) {
     Object.defineProperties(this, {
@@ -595,7 +605,6 @@ var GyroscopeRotationVectorSensor = function(data) {
 GyroscopeRotationVectorSensor.prototype = new Sensor();
 
 GyroscopeRotationVectorSensor.prototype.constructor = Sensor;
-
 // prettier-ignore
 GyroscopeRotationVectorSensor.prototype.getGyroscopeRotationVectorSensorData =
 function() {
@@ -647,7 +656,94 @@ LinearAccelerationSensor.prototype.getLinearAccelerationSensorData = function()
     );
 };
 
-////////////////////// Sensor Data classes//////////////////////
+//// MagneticUncalibratedSensor
+var MagneticUncalibratedSensor = function(data) {
+    Sensor.call(this, SensorType.MAGNETIC_UNCALIBRATED);
+};
+
+MagneticUncalibratedSensor.prototype = new Sensor();
+
+MagneticUncalibratedSensor.prototype.constructor = Sensor;
+
+MagneticUncalibratedSensor.prototype.getMagneticUncalibratedSensorData = 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)
+    );
+};
+
+//// GyroscopeUncalibratedSensor
+var GyroscopeUncalibratedSensor = function(data) {
+    Sensor.call(this, SensorType.GYROSCOPE_UNCALIBRATED);
+};
+
+GyroscopeUncalibratedSensor.prototype = new Sensor();
+
+GyroscopeUncalibratedSensor.prototype.constructor = Sensor;
+
+GyroscopeUncalibratedSensor.prototype.getGyroscopeUncalibratedSensorData = 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)
+    );
+};
+
+//// AccelerationSensor
+var AccelerationSensor = function(data) {
+    Sensor.call(this, SensorType.ACCELERATION);
+};
+
+AccelerationSensor.prototype = new Sensor();
+
+AccelerationSensor.prototype.constructor = Sensor;
+
+AccelerationSensor.prototype.getAccelerationSensorData = 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)
+    );
+};
+
+////////////////////// Sensor Data classes/////////////////////////////
 ////Base SensorData class
 var SensorData = function() {};
 
@@ -655,11 +751,7 @@ var SensorData = function() {};
 var SensorLightData = function(data) {
     SensorData.call(this);
     Object.defineProperties(this, {
-        lightLevel: {
-            value: data.lightLevel,
-            writable: false,
-            enumerable: true
-        }
+        lightLevel: { value: data.lightLevel, writable: false, enumerable: true }
     });
 };
 
@@ -713,11 +805,7 @@ _sensorListeners[SensorType.PRESSURE] = new SensorListener(
 var SensorProximityData = function(data) {
     SensorData.call(this);
     Object.defineProperties(this, {
-        proximityState: {
-            value: data.proximityState,
-            writable: false,
-            enumerable: true
-        }
+        proximityState: { value: data.proximityState, writable: false, enumerable: true }
     });
 };
 
@@ -756,11 +844,7 @@ var SensorHRMRawData = function(data) {
     SensorData.call(this);
     Object.defineProperties(this, {
         lightType: { value: data.lightType, writable: false, enumerable: true },
-        lightIntensity: {
-            value: data.lightIntensity,
-            writable: false,
-            enumerable: true
-        }
+        lightIntensity: { value: data.lightIntensity, writable: false, enumerable: true }
     });
 };
 
@@ -850,7 +934,70 @@ _sensorListeners[SensorType.LINEAR_ACCELERATION] = new SensorListener(
     SensorLinearAccelerationData
 );
 
-//////////////////////SensorHardwareInfo classes//////////////////////
+//// SensorMagneticUncalibratedData
+var SensorMagneticUncalibratedData = function(data) {
+    SensorData.call(this);
+    Object.defineProperties(this, {
+        x: { value: data.x, writable: false, enumerable: true },
+        y: { value: data.y, writable: false, enumerable: true },
+        z: { value: data.z, writable: false, enumerable: true },
+        xAxisBias: { value: data.xAxisBias, writable: false, enumerable: true },
+        yAxisBias: { value: data.yAxisBias, writable: false, enumerable: true },
+        zAxisBias: { value: data.zAxisBias, writable: false, enumerable: true }
+    });
+};
+
+SensorMagneticUncalibratedData.prototype = new SensorData();
+
+SensorMagneticUncalibratedData.prototype.constructor = SensorData;
+
+_sensorListeners[SensorType.MAGNETIC_UNCALIBRATED] = new SensorListener(
+    SensorType.MAGNETIC_UNCALIBRATED,
+    SensorMagneticUncalibratedData
+);
+
+//// SensorGyroscopeUncalibratedData
+var SensorGyroscopeUncalibratedData = function(data) {
+    SensorData.call(this);
+    Object.defineProperties(this, {
+        x: { value: data.x, writable: false, enumerable: true },
+        y: { value: data.y, writable: false, enumerable: true },
+        z: { value: data.z, writable: false, enumerable: true },
+        xAxisDrift: { value: data.xAxisDrift, writable: false, enumerable: true },
+        yAxisDrift: { value: data.yAxisDrift, writable: false, enumerable: true },
+        zAxisDrift: { value: data.zAxisDrift, writable: false, enumerable: true }
+    });
+};
+
+SensorGyroscopeUncalibratedData.prototype = new SensorData();
+
+SensorGyroscopeUncalibratedData.prototype.constructor = SensorData;
+
+_sensorListeners[SensorType.GYROSCOPE_UNCALIBRATED] = new SensorListener(
+    SensorType.GYROSCOPE_UNCALIBRATED,
+    SensorGyroscopeUncalibratedData
+);
+
+//// SensorAccelerationData
+var SensorAccelerationData = function(data) {
+    SensorData.call(this);
+    Object.defineProperties(this, {
+        x: { value: data.x, writable: false, enumerable: true },
+        y: { value: data.y, writable: false, enumerable: true },
+        z: { value: data.z, writable: false, enumerable: true }
+    });
+};
+
+SensorAccelerationData.prototype = new SensorData();
+
+SensorAccelerationData.prototype.constructor = SensorData;
+
+_sensorListeners[SensorType.ACCELERATION] = new SensorListener(
+    SensorType.ACCELERATION,
+    SensorAccelerationData
+);
+
+//////////////////////SensorHardwareInfo classes/////////////////////////////
 function SensorHardwareInfo(data) {
     Object.defineProperties(this, {
         name: { value: data.name, writable: false, enumerable: true },
@@ -858,21 +1005,9 @@ function SensorHardwareInfo(data) {
         vendor: { value: data.vendor, writable: false, enumerable: true },
         minValue: { value: data.minValue, writable: false, enumerable: true },
         maxValue: { value: data.maxValue, writable: false, enumerable: true },
-        resolution: {
-            value: data.resolution,
-            writable: false,
-            enumerable: true
-        },
-        minInterval: {
-            value: data.minInterval,
-            writable: false,
-            enumerable: true
-        },
-        maxBatchCount: {
-            value: data.batchCount,
-            writable: false,
-            enumerable: true
-        }
+        resolution: { value: data.resolution, writable: false, enumerable: true },
+        minInterval: { value: data.minInterval, writable: false, enumerable: true },
+        maxBatchCount: { value: data.batchCount, writable: false, enumerable: true }
     });
 }
 // Exports
index b6b87fe..1dcc339 100644 (file)
@@ -128,6 +128,30 @@ void ReportSensorData(sensor_type_e sensor_type, sensor_event_s* sensor_event,
       (*out)["z"] = picojson::value(static_cast<double>(sensor_event->values[2]));
       break;
     }
+    case SENSOR_GEOMAGNETIC_UNCALIBRATED: {
+      (*out)["x"] = picojson::value(static_cast<double>(sensor_event->values[0]));
+      (*out)["y"] = picojson::value(static_cast<double>(sensor_event->values[1]));
+      (*out)["z"] = picojson::value(static_cast<double>(sensor_event->values[2]));
+      (*out)["xAxisBias"] = picojson::value(static_cast<double>(sensor_event->values[3]));
+      (*out)["yAxisBias"] = picojson::value(static_cast<double>(sensor_event->values[4]));
+      (*out)["zAxisBias"] = picojson::value(static_cast<double>(sensor_event->values[5]));
+      break;
+    }
+    case SENSOR_GYROSCOPE_UNCALIBRATED: {
+      (*out)["x"] = picojson::value(static_cast<double>(sensor_event->values[0]));
+      (*out)["y"] = picojson::value(static_cast<double>(sensor_event->values[1]));
+      (*out)["z"] = picojson::value(static_cast<double>(sensor_event->values[2]));
+      (*out)["xAxisDrift"] = picojson::value(static_cast<double>(sensor_event->values[3]));
+      (*out)["yAxisDrift"] = picojson::value(static_cast<double>(sensor_event->values[4]));
+      (*out)["zAxisDrift"] = picojson::value(static_cast<double>(sensor_event->values[5]));
+      break;
+    }
+    case SENSOR_ACCELEROMETER: {
+      (*out)["x"] = picojson::value(static_cast<double>(sensor_event->values[0]));
+      (*out)["y"] = picojson::value(static_cast<double>(sensor_event->values[1]));
+      (*out)["z"] = picojson::value(static_cast<double>(sensor_event->values[2]));
+      break;
+    }
     default: {
       LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unsupported type"), out);
       return;
@@ -260,7 +284,7 @@ SensorData::SensorData(SensorInstance& instance, sensor_type_e type_enum, const
 }
 
 SensorData::~SensorData() {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
 
   if (listener_) {
     sensor_destroy_listener(listener_);
@@ -313,7 +337,7 @@ void SensorData::SensorCallback(sensor_h sensor, sensor_event_s* event, void* us
 }
 
 PlatformResult SensorData::CheckInitialization() {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
 
   std::lock_guard<std::mutex> lock(initialization_mutex_);
   if (!handle_) {
@@ -336,7 +360,7 @@ PlatformResult SensorData::CheckInitialization() {
 }
 
 PlatformResult SensorData::IsSupported(bool* supported) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
 
   if (!is_supported_) {
     bool is_supported = false;
@@ -353,7 +377,7 @@ PlatformResult SensorData::IsSupported(bool* supported) {
 }
 
 PlatformResult SensorData::IsSupportedImpl(bool* supported) const {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
 
   bool is_supported = false;
   int ret = sensor_is_supported(type_enum_, &is_supported);
@@ -368,7 +392,7 @@ PlatformResult SensorData::IsSupportedImpl(bool* supported) const {
 }
 
 bool SensorData::is_supported() {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
 
   if (!is_supported_) {
     bool is_supported = false;
@@ -384,7 +408,7 @@ bool SensorData::is_supported() {
 }
 
 bool SensorData::UpdateEvent(sensor_event_s* event) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
 
   if (comparator_(&previous_event_, event, sensor_value_count_)) {
     // previous and current events are the same -> no update
@@ -420,7 +444,7 @@ PlatformResult SensorData::AddDelayedStartSuccessCb(const std::function<void()>&
 PlatformResult SensorData::Start(
     const std::shared_ptr<picojson::value>& result,
     const std::function<void(const std::shared_ptr<picojson::value>&)>& report_result) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
   auto res = CheckInitialization();
 
   if (!res) {
@@ -460,7 +484,7 @@ PlatformResult SensorData::Start(
 }
 
 PlatformResult SensorData::Stop() {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
 
   auto res = CheckInitialization();
 
@@ -489,7 +513,7 @@ PlatformResult SensorData::Stop() {
 }
 
 PlatformResult SensorData::SetChangeListener(unsigned int interval, unsigned int batch_latency) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
 
   auto res = CheckInitialization();
 
@@ -520,7 +544,7 @@ PlatformResult SensorData::SetChangeListener(unsigned int interval, unsigned int
 }
 
 PlatformResult SensorData::UnsetChangeListener() {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
 
   auto res = CheckInitialization();
 
@@ -544,7 +568,7 @@ PlatformResult SensorData::UnsetChangeListener() {
 }
 
 PlatformResult SensorData::GetSensorData(picojson::object* data) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
 
   auto res = CheckInitialization();
 
@@ -566,7 +590,7 @@ PlatformResult SensorData::GetSensorData(picojson::object* data) {
 }
 
 PlatformResult SensorData::GetHardwareInfo(picojson::object* data) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
 
   auto res = CheckInitialization();
 
@@ -605,42 +629,42 @@ PlatformResult SensorData::GetHardwareInfo(picojson::object* data) {
 
   int ret = sensor_get_name(handle_, &name);
   if (ret != SENSOR_ERROR_NONE) {
-    LoggerE("Failed to sensor_get_name error code: %d", &ret);
+    LoggerE("Failed to sensor_get_name error code: %d", ret);
     return native_result(ret);
   }
   ret = sensor_get_vendor(handle_, &vendor);
   if (ret != SENSOR_ERROR_NONE) {
-    LoggerE("Failed to sensor_get_vendor error code: %d", &ret);
+    LoggerE("Failed to sensor_get_vendor error code: %d", ret);
     return native_result(ret);
   }
   ret = sensor_get_type(handle_, &type);
   if (ret != SENSOR_ERROR_NONE) {
-    LoggerE("Failed to sensor_get_type error code: %d", &ret);
+    LoggerE("Failed to sensor_get_type error code: %d", ret);
     return native_result(ret);
   }
   ret = sensor_get_min_range(handle_, &min_range);
   if (ret != SENSOR_ERROR_NONE) {
-    LoggerE("Failed to sensor_get_min_range error code: %d", &ret);
+    LoggerE("Failed to sensor_get_min_range error code: %d", ret);
     return native_result(ret);
   }
   ret = sensor_get_max_range(handle_, &max_range);
   if (ret != SENSOR_ERROR_NONE) {
-    LoggerE("Failed to sensor_get_max_range error code: %d", &ret);
+    LoggerE("Failed to sensor_get_max_range error code: %d", ret);
     return native_result(ret);
   }
   ret = sensor_get_resolution(handle_, &resolution);
   if (ret != SENSOR_ERROR_NONE) {
-    LoggerE("Failed to sensor_get_resolution error code: %d", &ret);
+    LoggerE("Failed to sensor_get_resolution error code: %d", ret);
     return native_result(ret);
   }
   ret = sensor_get_min_interval(handle_, &min_interval);
   if (ret != SENSOR_ERROR_NONE) {
-    LoggerE("Failed to sensor_get_min_interval error code: %d", &ret);
+    LoggerE("Failed to sensor_get_min_interval error code: %d", ret);
     return native_result(ret);
   }
   ret = sensor_get_max_batch_count(handle_, &max_batch_count);
   if (ret != SENSOR_ERROR_NONE) {
-    LoggerE("Failed to sensor_get_max_batch_count error code: %d", &ret);
+    LoggerE("Failed to sensor_get_max_batch_count error code: %d", ret);
     return native_result(ret);
   }
 
@@ -686,7 +710,7 @@ class HrmSensorData : public SensorData {
 
 HrmSensorData::HrmSensorData(SensorInstance& instance)
     : SensorData(instance, SENSOR_CUSTOM, "HRM_RAW", 1) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
   // For amount of retrieved values from sensors please refer to native guides.
   AddSensor(new SensorData(instance, SENSOR_HRM_LED_IR, "LED_IR", 1));
   AddSensor(new SensorData(instance, SENSOR_HRM_LED_RED, "LED_RED", 1));
@@ -694,16 +718,16 @@ HrmSensorData::HrmSensorData(SensorInstance& instance)
 }
 
 HrmSensorData::~HrmSensorData() {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
 }
 
 void HrmSensorData::AddSensor(SensorData* sensor) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
   hrm_sensors_.insert(std::make_pair(sensor->type(), std::shared_ptr<SensorData>(sensor)));
 }
 
 PlatformResult HrmSensorData::CallMember(PlatformResult (SensorData::*member)()) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
   bool is_any_supported = false;
   for (const auto& sensor : hrm_sensors_) {
     if (sensor.second->is_supported()) {
@@ -727,7 +751,7 @@ PlatformResult HrmSensorData::CallMember(
         const std::function<void(const std::shared_ptr<picojson::value>&)>&),
     const std::shared_ptr<picojson::value>& result,
     const std::function<void(const std::shared_ptr<picojson::value>&)>& work) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
   bool is_any_supported = false;
   for (const auto& sensor : hrm_sensors_) {
     if (sensor.second->is_supported()) {
@@ -746,16 +770,9 @@ PlatformResult HrmSensorData::CallMember(
 }
 
 PlatformResult HrmSensorData::IsSupportedImpl(bool* supported) const {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
   bool result = false;
 
-  bool hrm_supported = false;
-  int ret = sensor_is_supported(SENSOR_HRM, &hrm_supported);
-  if (ret == SENSOR_ERROR_NONE) {
-    LoggerD("HRM support is: %d", hrm_supported);
-    result |= hrm_supported;
-  }
-
   for (const auto& sensor : hrm_sensors_) {
     bool is_supported = false;
     auto res = sensor.second->IsSupported(&is_supported);
@@ -773,17 +790,17 @@ PlatformResult HrmSensorData::IsSupportedImpl(bool* supported) const {
 PlatformResult HrmSensorData::Start(
     const std::shared_ptr<picojson::value>& result,
     const std::function<void(const std::shared_ptr<picojson::value>&)>& work) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
   return CallMember(&SensorData::Start, result, work);
 }
 
 PlatformResult HrmSensorData::Stop() {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
   return CallMember(&SensorData::Stop);
 }
 
 PlatformResult HrmSensorData::SetChangeListener(unsigned int interval, unsigned int batch_latency) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
   for (const auto& sensor : hrm_sensors_) {
     if (sensor.second->is_supported()) {
       auto res = sensor.second->SetChangeListener(interval, batch_latency);
@@ -796,12 +813,12 @@ PlatformResult HrmSensorData::SetChangeListener(unsigned int interval, unsigned
 }
 
 PlatformResult HrmSensorData::UnsetChangeListener() {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
   return CallMember(&SensorData::UnsetChangeListener);
 }
 
 PlatformResult HrmSensorData::GetSensorData(picojson::object* data) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
   for (const auto& sensor : hrm_sensors_) {
     if (sensor.second->is_supported()) {
       // HRMRawSensor.getHRMRawSensorData() can return only one value,
@@ -823,7 +840,7 @@ PlatformResult HrmSensorData::GetSensorData(picojson::object* data) {
 }
 
 PlatformResult HrmSensorData::GetHardwareInfo(picojson::object* data) {
-  ScopeLogger(type_to_string_map[type()]);
+  ScopeLogger("type: %s", type_to_string_map[type()].c_str());
   for (const auto& sensor : hrm_sensors_) {
     if (sensor.second->is_supported()) {
       return sensor.second->GetHardwareInfo(data);
@@ -848,6 +865,9 @@ SensorService::SensorService(SensorInstance& instance) : instance_(instance) {
   AddSensor(
       new SensorData(instance, SENSOR_GYROSCOPE_ROTATION_VECTOR, "GYROSCOPE_ROTATION_VECTOR", 4));
   AddSensor(new SensorData(instance, SENSOR_LINEAR_ACCELERATION, "LINEAR_ACCELERATION", 3));
+  AddSensor(new SensorData(instance, SENSOR_GEOMAGNETIC_UNCALIBRATED, "MAGNETIC_UNCALIBRATED", 6));
+  AddSensor(new SensorData(instance, SENSOR_GYROSCOPE_UNCALIBRATED, "GYROSCOPE_UNCALIBRATED", 6));
+  AddSensor(new SensorData(instance, SENSOR_ACCELEROMETER, "ACCELERATION", 3));
 }
 
 SensorService::~SensorService() {
@@ -897,7 +917,6 @@ void SensorService::SensorStart(const picojson::value& args, picojson::object& o
 
   auto start = [this, type_enum, type_str,
                 start_result](const std::shared_ptr<picojson::value>& result) {
-
     ScopeLogger("Entered into asynchronous function, start");
     auto sensor_data = GetSensor(type_enum);
     if (!sensor_data) {
index 3174436..8c98163 100644 (file)
@@ -274,7 +274,7 @@ PlatformResult SoundManager::SetVolume(const picojson::object& args) {
   auto it = max_volume_map_.find(sound_type);
   if (it == max_volume_map_.end()) {
     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Failed to find maxVolume",
-                              ("Failed to find maxVolume of type: %d", type.c_str()));
+                              ("Failed to find maxVolume of type: %s", type.c_str()));
   }
 
   int max_volume = it->second;
index ae9d39f..5822c00 100644 (file)
@@ -47,9 +47,6 @@
             ]
           },
         }],
-        ['tizen_is_emulator == 1', {
-          'defines': ['TIZEN_IS_EMULATOR'],
-        }],
       ],
     },
   ],
index 19ef6fe..601f661 100644 (file)
@@ -424,6 +424,16 @@ function SystemInfoBattery(data) {
             value: data.isCharging,
             writable: false,
             enumerable: true
+        },
+        timeToDischarge: {
+            value: data.timeToDischarge,
+            writable: false,
+            enumerable: true
+        },
+        timeToFullCharge: {
+            value: data.timeToFullCharge,
+            writable: false,
+            enumerable: true
         }
     });
 }
@@ -468,10 +478,9 @@ function SystemInfoStorageUnit(data) {
             enumerable: true,
             get: function() {
                 privUtils_.warn(
-                    'DEPRECATION WARNING: ' +
-                        'SystemInfoStorageUnit.isRemoveable is is deprecated and ' +
-                        'will be removed from next release. Use ' +
-                        'SystemInfoStorageUnit.isRemovable instead.'
+                    'DEPRECATION WARNING: SystemInfoStorageUnit.isRemoveable is ' +
+                        'deprecated and will be removed from next release. ' +
+                        'Use SystemInfoStorageUnit.isRemovable instead.'
                 );
                 return _isRemovable;
             },
@@ -780,8 +789,8 @@ var SystemInfo = function() {};
 
 SystemInfo.prototype.getCapabilities = function() {
     privUtils_.warn(
-        'DEPRECATION WARNING: getCapabilities() is deprecated ' +
-            'and will be removed from next release. Use getCapability() instead.'
+        'DEPRECATION WARNING: getCapabilities() is deprecated and will be removed ' +
+            'from next release. Use getCapability() instead.'
     );
 
     var result = native_.callSync('SystemInfo_getCapabilities', {});
@@ -968,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 5f537ee..7c272fa 100644 (file)
@@ -62,6 +62,7 @@ const char* kPlatformCoreSse3 = "sse3";
 const char* kPlatformCoreSsse3 = "ssse3";
 const char* kPlatformCoreVfpv2 = "vfpv2";
 const char* kPlatformCoreVfpv3 = "vfpv3";
+const char* kPlatformCoreVfpv4 = "vfpv4";
 
 /*API feature*/
 /*Network feature*/
@@ -528,6 +529,17 @@ PlatformResult SystemInfoDeviceCapability::GetPlatfomCoreFpuArch(std::string* re
     }
     result += kPlatformCoreVfpv3;
   }
+
+  ret = GetValueBool("tizen.org/feature/platform.core.fpu.arch.vfpv4", &bool_result);
+  if (ret.IsError()) {
+    return ret;
+  }
+  if (bool_result) {
+    if (!result.empty()) {
+      result += kPlatformCoreDelimiter;
+    }
+    result += kPlatformCoreVfpv4;
+  }
   if (result.empty()) {
     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "platformCoreFpuArch result is empty");
   }
@@ -578,17 +590,40 @@ bool SystemInfoDeviceCapability::IsScreen() {
   return true;
 }
 
+#define MODEL_NAME "http://tizen.org/system/model_name"
+#define MODEL_EMULATOR "Emulator"
+bool _is_emulator(void) {
+  int ret;
+  char* model_name = NULL;
+  static bool emul = false;
+  static int set = 0;
+
+  if (set) return emul;
+
+  ret = system_info_get_platform_string(MODEL_NAME, &model_name);
+  if (ret < 0) {
+    LoggerD("Cannot get model name(%d)", ret);
+    return emul;
+  }
+
+  if (!strncmp(MODEL_EMULATOR, model_name, strlen(model_name) + 1)) emul = true;
+
+  set = 1;
+  free(model_name);
+
+  return emul;
+}
+
 PlatformResult SystemInfoDeviceCapability::GetPlatformCoreCpuFrequency(int* return_value) {
   ScopeLogger();
 
   std::string freq;
   std::string file_name;
 
-#ifdef TIZEN_IS_EMULATOR
-  file_name = "/proc/cpuinfo";
-#else
-  file_name = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
-#endif
+  if (_is_emulator())
+    file_name = "/proc/cpuinfo";
+  else
+    file_name = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
 
   std::ifstream cpuinfo_freq(file_name);
   if (!cpuinfo_freq.is_open()) {
@@ -596,24 +631,24 @@ PlatformResult SystemInfoDeviceCapability::GetPlatformCoreCpuFrequency(int* retu
                               ("Failed to get cpu frequency"));
   }
 
-#ifdef TIZEN_IS_EMULATOR
-  // get frequency value from cpuinfo file
-  // example entry for frequency looks like below
-  // cpu MHz   : 3392.046
-  std::size_t found;
-  do {
-    getline(cpuinfo_freq, freq);
-    found = freq.find("cpu MHz");
-  } while (std::string::npos == found && !cpuinfo_freq.eof());
+  if (_is_emulator()) {
+    // get frequency value from cpuinfo file
+    // example entry for frequency looks like below
+    // cpu MHz   : 3392.046
+    std::size_t found;
+    do {
+      getline(cpuinfo_freq, freq);
+      found = freq.find("cpu MHz");
+    } while (std::string::npos == found && !cpuinfo_freq.eof());
 
-  found = freq.find(":");
-  if (std::string::npos != found) {
-    *return_value = std::stoi(freq.substr(found + 2));
+    found = freq.find(":");
+    if (std::string::npos != found) {
+      *return_value = std::stoi(freq.substr(found + 2));
+    }
+  } else {
+    getline(cpuinfo_freq, freq);
+    *return_value = std::stoi(freq) / 1000;  // unit: MHz
   }
-#else
-  getline(cpuinfo_freq, freq);
-  *return_value = std::stoi(freq) / 1000;  // unit: MHz
-#endif
 
   cpuinfo_freq.close();
   LoggerD("cpu frequency : %d", *return_value);
index 2dc2be7..5d7988f 100644 (file)
@@ -298,16 +298,17 @@ class SysteminfoManager::TapiManager {
 
     std::lock_guard<std::mutex> lock(mutex_);
 
+    PlatformResult first_error = PlatformResult{ErrorCode::NO_ERROR};
     for (const auto& h : handles_) {
       for (const auto& n : kNotifications) {
         auto result = SysteminfoUtils::UnregisterTapiChangeCallback(h, n);
-        if (!result) {
-          return result;
+        if (!result && first_error) {
+          first_error = result;
         }
       }
     }
 
-    return PlatformResult{ErrorCode::NO_ERROR};
+    return first_error;
   }
 
   PlatformResult GetNetworkType(std::size_t index, int* network_type) {
@@ -499,15 +500,15 @@ SysteminfoManager::~SysteminfoManager() {
     UnregisterNetworkListener();
   }
   if (IsListenerRegistered(kPropertyIdWifiNetwork)) {
-    registered_listeners_.erase(kPropertyIdWifiNetwork) /*HACK*/;
+    registered_listeners_.erase(kPropertyIdWifiNetwork);
     UnregisterWifiNetworkListener();
   }
   if (IsListenerRegistered(kPropertyIdEthernetNetwork)) {
-    registered_listeners_.erase(kPropertyIdEthernetNetwork) /*HACK*/;
+    registered_listeners_.erase(kPropertyIdEthernetNetwork);
     UnregisterEthernetNetworkListener();
   }
   if (IsListenerRegistered(kPropertyIdCellularNetwork)) {
-    registered_listeners_.erase(kPropertyIdCellularNetwork) /*HACK*/;
+    registered_listeners_.erase(kPropertyIdCellularNetwork);
     UnregisterCellularNetworkListener();
   }
   if (IsListenerRegistered(kPropertyIdPeripheral)) {
@@ -941,17 +942,25 @@ PlatformResult SysteminfoManager::RegisterBatteryListener() {
   PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR);
   CHECK_LISTENER_ERROR(SysteminfoUtils::RegisterVconfCallback(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
                                                               OnBatteryChangedCb, this))
-  CHECK_LISTENER_ERROR(SysteminfoUtils::RegisterVconfCallback(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
-                                                              OnBatteryChangedCb, this))
+  ret = SysteminfoUtils::RegisterVconfCallback(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
+                                               OnBatteryChangedCb, this);
+  if (ret.IsError()) {
+    SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_SYSMAN_BATTERY_CAPACITY, OnBatteryChangedCb);
+    return ret;
+  }
   LoggerD("Added callback for BATTERY");
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
 PlatformResult SysteminfoManager::UnregisterBatteryListener() {
   ScopeLogger();
-  PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR);
-  CHECK_LISTENER_ERROR(SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
-                                                                OnBatteryChangedCb))
+  PlatformResult ret = SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
+                                                                OnBatteryChangedCb);
+  if (ret.IsError()) {
+    SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
+                                             OnBatteryChangedCb);
+    return ret;
+  }
   CHECK_LISTENER_ERROR(SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
                                                                 OnBatteryChangedCb))
   LoggerD("Removed callback for BATTERY");
@@ -986,10 +995,11 @@ PlatformResult SysteminfoManager::RegisterStorageListener() {
 
 PlatformResult SysteminfoManager::UnregisterStorageListener() {
   ScopeLogger();
-  PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR);
-
   g_source_remove(storage_event_id_);
   storage_event_id_ = 0;
+
+  PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR);
+
   LoggerD("Removed callback for STORAGE");
   return PlatformResult(ErrorCode::NO_ERROR);
 }
@@ -1022,9 +1032,11 @@ PlatformResult SysteminfoManager::RegisterDeviceOrientationListener() {
       sensord_register_event(GetSensorHandle(), AUTO_ROTATION_EVENT_CHANGE_STATE,
                              BASE_GATHERING_INTERVAL, 0, OnDeviceOrientationChangedCb, this);
   if (!sensor_ret) {
-    return LogAndCreateResult(
-        ErrorCode::UNKNOWN_ERR, "Failed to register orientation change event listener",
-        ("sensord_register_event error: %d (%s)", sensor_ret, get_error_message(sensor_ret)));
+    SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL,
+                                             OnDeviceAutoRotationChangedCb);
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
+                              "Failed to register orientation change event listener",
+                              ("sensord_register_event returned false"));
   }
 
   LoggerD("Added callback for DEVICE_ORIENTATION");
@@ -1033,15 +1045,17 @@ PlatformResult SysteminfoManager::RegisterDeviceOrientationListener() {
 
 PlatformResult SysteminfoManager::UnregisterDeviceOrientationListener() {
   ScopeLogger();
-  PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR);
-  CHECK_LISTENER_ERROR(SysteminfoUtils::UnregisterVconfCallback(
-      VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, OnDeviceAutoRotationChangedCb))
   bool sensor_ret = sensord_unregister_event(GetSensorHandle(), AUTO_ROTATION_EVENT_CHANGE_STATE);
   if (!sensor_ret) {
-    return LogAndCreateResult(
-        ErrorCode::UNKNOWN_ERR, "Failed to unregister orientation change event listener",
-        ("sensord_unregister_event error: %d (%s)", sensor_ret, get_error_message(sensor_ret)));
+    SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL,
+                                             OnDeviceAutoRotationChangedCb);
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
+                              "Failed to unregister orientation change event listener",
+                              ("sensord_unregister_event returned false"));
   }
+  PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR);
+  CHECK_LISTENER_ERROR(SysteminfoUtils::UnregisterVconfCallback(
+      VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, OnDeviceAutoRotationChangedCb))
 
   LoggerD("Removed callback for DEVICE_ORIENTATION");
   return PlatformResult(ErrorCode::NO_ERROR);
@@ -1052,17 +1066,23 @@ PlatformResult SysteminfoManager::RegisterLocaleListener() {
   PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR);
   CHECK_LISTENER_ERROR(
       SysteminfoUtils::RegisterVconfCallback(VCONFKEY_REGIONFORMAT, OnLocaleChangedCb, this))
-  CHECK_LISTENER_ERROR(
-      SysteminfoUtils::RegisterVconfCallback(VCONFKEY_LANGSET, OnLocaleChangedCb, this))
+  ret = SysteminfoUtils::RegisterVconfCallback(VCONFKEY_LANGSET, OnLocaleChangedCb, this);
+  if (ret.IsError()) {
+    SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_REGIONFORMAT, OnLocaleChangedCb);
+    return ret;
+  }
   LoggerD("Added callback for LOCALE");
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
 PlatformResult SysteminfoManager::UnregisterLocaleListener() {
   ScopeLogger();
-  PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR);
-  CHECK_LISTENER_ERROR(
-      SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_REGIONFORMAT, OnLocaleChangedCb))
+  PlatformResult ret =
+      SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_REGIONFORMAT, OnLocaleChangedCb);
+  if (ret.IsError()) {
+    SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_LANGSET, OnLocaleChangedCb);
+    return ret;
+  }
   CHECK_LISTENER_ERROR(
       SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_LANGSET, OnLocaleChangedCb))
 
@@ -1190,10 +1210,15 @@ PlatformResult SysteminfoManager::UnregisterCellularNetworkListener() {
 
   // if there is no other ip-relateded listeners left, unregister
   if (!IsListenerRegistered(kPropertyIdCellularNetwork)) {
-    PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR);
-    CHECK_LISTENER_ERROR(SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_TELEPHONY_FLIGHT_MODE,
-                                                                  OnCellularNetworkValueChangedCb))
-
+    PlatformResult ret = SysteminfoUtils::UnregisterVconfCallback(VCONFKEY_TELEPHONY_FLIGHT_MODE,
+                                                                  OnCellularNetworkValueChangedCb);
+    if (ret.IsError()) {
+      tapi_manager_->UnregisterCallbacks();
+      if (IsIpChangeCallbackNotRegistered()) {
+        UnregisterIpChangeCallback();
+      }
+      return ret;
+    }
     CHECK_LISTENER_ERROR(tapi_manager_->UnregisterCallbacks());
   }
 
index ce87eac..da705eb 100644 (file)
@@ -27,6 +27,7 @@
 #include <vconf-internal-keys.h>
 #include <vconf.h>
 
+#include "common/GDBus/connection.h"
 #include "common/filesystem/filesystem_provider.h"
 #include "common/scope_exit.h"
 #include "systeminfo/systeminfo-utils.h"
@@ -46,6 +47,11 @@ const double kDisplayInchToMillimeter = 25.4;
 // Battery
 const double kRemainingBatteryChargeMax = 100.0;
 const int kVconfErrorNone = 0;
+const char* kBatteryTarget = "org.tizen.resourced";
+const char* kBatteryObject = "/Org/Tizen/ResourceD/Logging";
+const char* kBatteryInterface = "org.tizen.resourced.logging";
+const char* kBatteryGetBatteryChargingTime = "GetBatteryChargingTime";
+const char* kBatteryGetBatteryRemainingTime = "GetBatteryRemainingTime";
 // Display
 const double kDisplayBrightnessDivideValue = 100;
 // Device Orientation
@@ -125,7 +131,7 @@ PlatformResult SysteminfoPropertiesManager::GetPropertyValue(const std::string&
       return ret;
     }
     LoggerD("property name: %s", property.c_str());
-    LoggerD("available property count: %d", property_count);
+    LoggerD("available property count: %lu", property_count);
 
     for (std::size_t i = 0; i < property_count; i++) {
       picojson::value result = picojson::value(picojson::object());
@@ -208,7 +214,51 @@ PlatformResult SysteminfoPropertiesManager::ReportBattery(picojson::object* out)
     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, (log_msg + std::to_string(ret)),
                               ("vconf_get_int error: %d (%s)", ret, get_error_message(ret)));
   }
-  out->insert(std::make_pair("isCharging", picojson::value(0 != value)));
+  bool isCharging = (0 != value);
+  out->insert(std::make_pair("isCharging", picojson::value(isCharging)));
+
+  if (nullptr == common::dbus::Connection::getInstance().getDBus()) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "dbus wasn't initialized");
+  }
+
+  GError* error = nullptr;
+  GVariant* variant = nullptr;
+  if (isCharging) {
+    variant = g_dbus_connection_call_sync(common::dbus::Connection::getInstance().getDBus(),
+                                          kBatteryTarget, kBatteryObject, kBatteryInterface,
+                                          kBatteryGetBatteryChargingTime, g_variant_new("()"), NULL,
+                                          G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
+  } else {
+    variant = g_dbus_connection_call_sync(common::dbus::Connection::getInstance().getDBus(),
+                                          kBatteryTarget, kBatteryObject, kBatteryInterface,
+                                          kBatteryGetBatteryRemainingTime,
+                                          g_variant_new("(i)", 0),  // 0 - POWER_NORMAL_MODE
+                                          NULL,                     // 1 - POWER_SAVING_MODE
+                                          G_DBUS_CALL_FLAGS_NONE,   // 2 - ULTRA_SAVING_MODE
+                                          -1,                       // for now, only 0 is supported
+                                          NULL, &error);
+  }
+
+  if (!variant || error) {
+    std::string message = error ? error->message : "";
+    g_error_free(error);
+    return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "DBus returned error",
+        ("Failed to call %s method - %s",
+         isCharging ? "GetBatteryChargingTime" : "GetBatteryRemainingTime", message.c_str()));
+  } else {
+    int time = 0;
+    g_variant_get(variant, "(i)", &time);
+    g_variant_unref(variant);
+    if (isCharging) {
+      out->insert(std::make_pair("timeToFullCharge", picojson::value(static_cast<double>(time))));
+      out->insert(std::make_pair("timeToDischarge", picojson::value()));
+    } else {
+      out->insert(std::make_pair("timeToFullCharge", picojson::value()));
+      out->insert(std::make_pair("timeToDischarge", picojson::value(static_cast<double>(time))));
+    }
+  }
+
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
@@ -397,7 +447,7 @@ PlatformResult SysteminfoPropertiesManager::FetchStatus(std::string* result) {
       break;
     default:
       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Received unexpected data",
-                                ("Received unexpected data: %u", rotation));
+                                ("Received unexpected data: %d", rotation));
   }
   *result = status;
   return PlatformResult(ErrorCode::NO_ERROR);
@@ -506,7 +556,7 @@ static PlatformResult GetNetworkTypeString(NetworkType type, std::string& type_s
 
 PlatformResult SysteminfoPropertiesManager::ReportNetwork(picojson::object* out,
                                                           unsigned long count) {
-  ScopeLogger("index property %d", count);
+  ScopeLogger("index property %lu", count);
   connection_h connection_handle = nullptr;
   connection_type_e connection_type = CONNECTION_TYPE_DISCONNECTED;
   int networkType = 0;
index 1d32c23..6522110 100644 (file)
@@ -132,7 +132,7 @@ PlatformResult TimeManager::UnregisterVconfCallback(ListenerType type) {
   if (!is_time_listener_registered_ && !is_timezone_listener_registered_) {
     LoggerD("unregistering listener on platform");
     if (0 != vconf_ignore_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, OnTimeChangedCallback)) {
-      LOGE("Failed to unregister vconf callback");
+      LoggerE("Failed to unregister vconf callback");
       // silent fail
       // return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Failed to unregister vconf callback");
     }
index 407e545..196dce8 100755 (executable)
             ],
           },
         ],
+        [
+          'tizen_feature_voicecontrol_support==1', {
+            'dependencies': [
+              'voicecontrol/voicecontrol.gyp:*',
+            ],
+          },
+        ],
+        [
+          'tizen_feature_ppm_support==1', {
+            'dependencies': [
+              'ppm/ppm.gyp:*',
+            ],
+          },
+        ],
       ], # end conditions
     },
   ], # end targets
index bed11fc..bad69c9 100644 (file)
@@ -154,6 +154,8 @@ Utils.prototype.error = console.error.bind(console);
 Utils.prototype.warn = console.warn.bind(console);
 Utils.prototype.log = _enableJsLogs ? console.log.bind(console) : function() {};
 
+Utils.prototype.global = _global;
+
 Utils.prototype.repackFilter = function(filter) {
     if (filter instanceof tizen.AttributeFilter) {
         return {
@@ -301,6 +303,12 @@ Utils.prototype.checkBackwardCompabilityPrivilegeAccess = function(
     }
 };
 
+Utils.prototype.checkProfile = function() {
+    var result = native_.callSync('Utils_checkProfile', {});
+
+    return native_.getResultObject(result);
+};
+
 /////////////////////////////////////////////////////////////////////////////
 /** @constructor */
 var Type = function() {};
@@ -638,8 +646,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
@@ -717,7 +725,7 @@ var Validator = function() {
  *     name: 'first',
  *     type: Validator.Types.ARRAY,
  *     values: Validator.Types.DOUBLE // converts elements,
- *                                    // only primitive types are supported
+ *              only primitive types are supported
  *   }
  * ]
  * @code
@@ -1246,270 +1254,6 @@ NativeManager.prototype.callIfPossible = function(callback) {
     }
 };
 
-/*
- *bridge is a two way communication interface
- *Example usage:
- *var bridge = new NativeBridge(extension);
- *    To send sync method:
- *    var result = bridge.sync({
- *        cmd: 'my_cpp_function_symbol',
- *        args: {
- *            name: 'My name',
- *            age: 28
- *        }
- *    });
- *    xwalk.utils.log(result);
- *
- *    To send async method and handle response:
- *    bridge.async({
- *        cmd: 'my_cpp_function_symbol',
- *        args: {
- *            name: 'My name'
- *        }
- *    }).then({
- *        success: function (data) {
- *            var age = data.age;
- *            args.successCallback(age);
- *        },
- *        error: function (e) {...},
- *        someCallback: function (data) {...}
- *    });
- *bridge.async will add special param to passed data called cid
- *that param need to be kept and returned with respons
- *To determine which callback should be invoked, response should
- *contain "action" param. Value of "action" param indicates name of
- *triggered callback.
- *Callbask are removed from listenr by defoult to prevent that behaviour
- *param "keep" should be assigned to value true
- *Example of c++ async response:
- *    Simple succes with data:
- *    {
- *        cid: 23,
- *        action: 'success',
- *        args: {
- *            age: 23
- *        }
- *    }
- *    More complicated example:
- *    {
- *        cid: 23,
- *        action: 'progress',
- *        keep: true,
- *        args: {
- *            age: 23
- *        }
- *    }
- */
-var NativeBridge = function(extension, debug) {
-    debug = !!debug;
-    var Callbacks = (function() {
-        var _collection = {};
-        var _cid = 0;
-        var _next = function() {
-            return (_cid += 1);
-        };
-
-        var CallbackManager = function() {};
-
-        CallbackManager.prototype = {
-            add: function(/*callbacks, cid?*/) {
-                if (debug) xwalk.utils.log('bridge.CallbackManager.add');
-                var args = Array.prototype.slice.call(arguments);
-                var c = args.shift();
-                var cid = args.pop();
-                if (cid) {
-                    if (c !== null && typeof c === 'object') {
-                        for (var key in c) {
-                            if (c.hasOwnProperty(key)) _collection[cid][key] = c[key];
-                        }
-                    }
-                } else {
-                    cid = _next();
-                    _collection[cid] = c;
-                }
-                return cid;
-            },
-            remove: function(cid) {
-                if (debug) {
-                    xwalk.utils.log('bridge.CallbackManager.remove, cid: ' + cid);
-                }
-                if (_collection[cid]) delete _collection[cid];
-            },
-            call: function(cid, key, args, keep) {
-                if (debug) {
-                    xwalk.utils.log(
-                        'bridge.CallbackManager.call, cid: ' + cid + ', key: ' + key
-                    );
-                }
-                var callbacks = _collection[cid];
-                keep = !!keep;
-                if (callbacks) {
-                    var fn = callbacks[key];
-                    if (fn) {
-                        fn.apply(null, args);
-                        if (!keep) this.remove(cid);
-                    }
-                }
-            }
-        };
-
-        return {
-            getInstance: function() {
-                return this.instance || (this.instance = new CallbackManager());
-            }
-        };
-    })();
-
-    var Listeners = (function() {
-        var _listeners = {};
-        var _id = 0;
-        var _next = function() {
-            return (_id += 1);
-        };
-
-        var ListenerManager = function() {};
-
-        ListenerManager.prototype = {
-            add: function(l) {
-                if (debug) xwalk.utils.log('bridge.ListenerManager.add');
-                var id = _next();
-                _listeners[id] = l;
-                return id;
-            },
-            resolve: function(id, action, data, keep) {
-                if (debug)
-                    xwalk.utils.log(
-                        'bridge.ListenerManager.resolve, id: ' +
-                            id +
-                            ', action: ' +
-                            action
-                    );
-                keep = !!keep;
-                var l = _listeners[id];
-                if (l) {
-                    var cm = Callbacks.getInstance();
-                    cm.call(l.cid, action, [data], keep);
-                }
-                return l;
-            },
-            remove: function(id) {
-                if (debug) xwalk.utils.log('bridge.ListenerManager.remove, id: ' + id);
-                var l = _listeners[id];
-                if (l) {
-                    var cm = Callbacks.getInstance();
-                    if (l.cid) cm.remove(l.cid);
-                    delete _listeners[id];
-                }
-            },
-            attach: function(id, key, value) {
-                if (_listeners[id]) {
-                    _listeners[id][key] = value;
-                    return true;
-                }
-                return false;
-            },
-            find: function(key, value) {
-                var result = [];
-                for (var p in _listeners) {
-                    if (_listeners.hasOwnProperty(p)) {
-                        var l = _listeners[p];
-                        if (l[key] === value) result.push({ id: p, listener: l });
-                    }
-                }
-                return result;
-            }
-        };
-
-        return {
-            getInstance: function() {
-                return this.instance || (this.instance = new ListenerManager());
-            }
-        };
-    })();
-
-    var Listener = function() {
-        if (debug) xwalk.utils.log('bridge: Listener constructor');
-        this.cid = null;
-    };
-    Listener.prototype = {
-        then: function(c) {
-            if (debug) xwalk.utils.log('bridge.Listener.then');
-            var cm = Callbacks.getInstance();
-            this.cid = cm.add(c, this.cid);
-            return this;
-        }
-    };
-
-    var Bridge = function() {};
-    Bridge.prototype = {
-        sync: function(data) {
-            var json = JSON_.stringify({
-                cmd: data.cmd,
-                args: data
-            });
-            if (debug) xwalk.utilss.log('bridge.sync, json: ' + json);
-            var result = extension.internal.sendSyncMessage(json);
-            var obj = JSON_.parse(result);
-            if (obj.error) throw new WebAPIException(obj.code, obj.name, obj.message);
-            return obj.result;
-        },
-        async: function(data) {
-            var l = new Listener();
-            data.cid = Listeners.getInstance().add(l);
-            var json = JSON_.stringify({
-                cmd: data.cmd,
-                args: data
-            });
-            if (debug) xwalk.utils.log('bridge.async, json: ' + json);
-            setTimeout(function() {
-                extension.postMessage(json);
-            });
-            return l;
-        },
-        listener: function(c) {
-            var l = new Listener().then(c);
-            var cid = Listeners.getInstance().add(l);
-            return cid;
-        },
-        attach: function(id, key, value) {
-            return Listeners.getInstance().attach(id, key, value);
-        },
-        find: function(key, value) {
-            return Listeners.getInstance().find(key, value);
-        },
-        remove: function(id) {
-            Listeners.getInstance().remove(id);
-        }
-    };
-
-    extension.setMessageListener(function(json) {
-        /*
-         *Expected response:
-         *{
-         *    cid: 23,                        // callback id
-         *    action: 'success',              // expected callback action
-         *    keep: false                     // optional param
-         *    args: {...}                     // data pased to callback
-         *}
-         */
-
-        if (debug) xwalk.utils.log('bridge.setMessageListener, json: ' + json);
-        var data = JSON_.parse(json);
-        if (data.cid && data.action) {
-            setTimeout(function() {
-                Listeners.getInstance().resolve(
-                    data.cid,
-                    data.action,
-                    data.args,
-                    data.keep
-                );
-            }, 0);
-        }
-    });
-
-    return new Bridge();
-};
-
 // WebAPIException and WebAPIError definition moved to Utils for compliance
 // reasons with blink-wrt environment.
 // In blink-wrt the original Tizen module is loaded,
@@ -1616,8 +1360,8 @@ Object.keys(errors).forEach(function(key) {
  * Generic exception interface.
  *
  * @param {number} code 16-bit error code.
- * @param {string} message An error message that describes the details
- *                          of an encountered error.
+ * @param {string} message An error message that describes the details of
+ *                          an encountered error.
  * @param {string} name An error type.
  */
 var WebAPIException = function(code, message, name) {
@@ -1712,7 +1456,6 @@ Utils.prototype.type = _type;
 Utils.prototype.converter = _converter;
 Utils.prototype.validator = _validator;
 Utils.prototype.NativeManager = NativeManager;
-Utils.prototype.NativeBridge = NativeBridge;
 
 var native_ = new NativeManager(extension);
 
@@ -1722,4 +1465,3 @@ Object.freeze(exports);
 Object.freeze(exports.utils);
 Object.freeze(Utils.prototype);
 Object.freeze(NativeManager.prototype);
-Object.freeze(NativeBridge.prototype);
index 65f5995..9cb9dd5 100644 (file)
@@ -33,6 +33,7 @@ UtilsInstance::UtilsInstance() {
                 CheckBackwardCompabilityPrivilegeAccess);
   REGISTER_SYNC("Utils_toLongLong", ToLongLong);
   REGISTER_SYNC("Utils_toUnsignedLongLong", ToUnsignedLongLong);
+  REGISTER_SYNC("Utils_checkProfile", CheckProfile);
 
 #undef REGISTER_SYNC
 #undef REGISTER_ASYNC
@@ -116,5 +117,22 @@ void UtilsInstance::ToUnsignedLongLong(const picojson::value& args, picojson::ob
   ReportSuccess(picojson::value(static_cast<double>(output)), out);
 }
 
+void UtilsInstance::CheckProfile(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  std::string profile = "common";
+#if defined(TIZEN_MOBILE)
+  profile = "mobile";
+#elif defined(TIZEN_WEARABLE)
+  profile = "wearable";
+#elif defined(TIZEN_TV) || defined(USBHOST)
+  profile = "tv";
+#elif defined(TIZEN_IVI)
+  profile = "ivi";
+#endif
+
+  ReportSuccess(picojson::value(profile), out);
+}
+
 }  // namespace utils
 }  // namespace extension
index fee0d41..c39a91d 100644 (file)
@@ -24,6 +24,7 @@ class UtilsInstance : public common::ParsedInstance {
 
   void ToLongLong(const picojson::value& args, picojson::object& out);
   void ToUnsignedLongLong(const picojson::value& args, picojson::object& out);
+  void CheckProfile(const picojson::value& args, picojson::object& out);
 };
 }  // namespace utils
 }  // namespace extension
diff --git a/src/voicecontrol/voicecontrol.gyp b/src/voicecontrol/voicecontrol.gyp
new file mode 100755 (executable)
index 0000000..8706d51
--- /dev/null
@@ -0,0 +1,34 @@
+{
+  'includes':[
+    '../common/common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'tizen_voicecontrol',
+      'type': 'loadable_module',
+      'dependencies': [
+        '../common/common.gyp:tizen_common',
+      ],
+      'sources': [
+        'voicecontrol_api.js',
+        'voicecontrol_client.cc',
+        'voicecontrol_client.h',
+        'voicecontrol_extension.cc',
+        'voicecontrol_extension.h',
+        'voicecontrol_instance.cc',
+        'voicecontrol_instance.h',
+        'voicecontrol_util.cc',
+        'voicecontrol_util.cc'
+      ],
+      'conditions': [
+        ['tizen == 1', {
+          'variables': {
+            'packages': [
+              'voice-control'
+            ]
+          },
+        }],
+      ],
+    },
+  ],
+}
diff --git a/src/voicecontrol/voicecontrol_api.js b/src/voicecontrol/voicecontrol_api.js
new file mode 100755 (executable)
index 0000000..a0ab77a
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+var utils_ = xwalk.utils;
+var type_ = utils_.type;
+var converter_ = utils_.converter;
+var validator_ = utils_.validator;
+var types_ = validator_.Types;
+var native_ = new xwalk.utils.NativeManager(extension);
+
+function ListenerManager(native, listenerName, handle) {
+    this.listeners = {};
+    this.nextId = 1;
+    this.nativeSet = false;
+    this.native = native;
+    this.listenerName = listenerName;
+    this.handle = handle || function(msg, listener, watchId) {};
+}
+
+ListenerManager.prototype.addListener = function(callback, nativeCall, data) {
+    var id = this.nextId;
+    if (!this.nativeSet) {
+        this.native.addListener(
+            this.listenerName,
+            function(msg) {
+                for (var watchId in this.listeners) {
+                    if (this.listeners.hasOwnProperty(watchId)) {
+                        this.handle(msg, this.listeners[watchId], watchId);
+                    }
+                }
+            }.bind(this)
+        );
+        var result = this.native.callSync(nativeCall, data || {});
+        if (this.native.isFailure(result)) {
+            throw this.native.getErrorObject(result);
+        }
+        this.nativeSet = true;
+    }
+
+    this.listeners[id] = callback;
+    ++this.nextId;
+
+    return id;
+};
+
+ListenerManager.prototype.removeListener = function(watchId, nativeCall) {
+    if (this.listeners.hasOwnProperty(watchId)) {
+        delete this.listeners[watchId];
+    }
+
+    if (this.nativeSet && type_.isEmptyObject(this.listeners)) {
+        this.native.callSync(nativeCall);
+        this.native.removeListener(this.listenerName);
+        this.nativeSet = false;
+    }
+};
+
+ListenerManager.prototype.removeAllListeners = function() {
+    this.native.removeListener(this.listenerName);
+    this.listeners = {};
+    this.nativeSet = false;
+};
+
+var VcResultListener = new ListenerManager(native_, 'onresult', function(
+    result,
+    listener
+) {
+    listener(result.event, result.list, result.results);
+});
+
+var VcLangListener = new ListenerManager(native_, 'onlanguagechanged', function(
+    result,
+    listener
+) {
+    listener(result.previous, result.current);
+});
+
+var VoiceControlResultEvent = {
+    SUCCESS: 'SUCCESS',
+    FAILURE: 'FAILURE'
+};
+
+var VoiceControlCommandType = {
+    FOREGROUND: 'FOREGROUND'
+};
+
+function VoiceControlClientManager() {}
+
+VoiceControlClientManager.prototype.getVoiceControlClient = function() {
+    var result = native_.callSync('VoiceControlClientManager_getVoiceControlClient', {});
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+
+    return new VoiceControlClient();
+};
+
+function VoiceControlClient() {}
+
+VoiceControlClient.prototype.getCurrentLanguage = function() {
+    var result = native_.callSync('VoiceControlClient_getCurrentLanguage', {});
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+
+    return native_.getResultObject(result);
+};
+
+VoiceControlClient.prototype.setCommandList = function(list, type) {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'list', type: types_.ARRAY, values: VoiceControlCommand },
+        {
+            name: 'type',
+            type: types_.ENUM,
+            values: type_.getValues(VoiceControlCommandType),
+            optional: true,
+            nullable: true
+        }
+    ]);
+
+    if (type_.isNullOrUndefined(args.type)) {
+        args.type = VoiceControlCommandType.FOREGROUND;
+    }
+
+    var data = {
+        list: args.list,
+        type: args.type
+    };
+
+    var result = native_.callSync('VoiceControlClient_setCommandList', data);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+};
+
+VoiceControlClient.prototype.unsetCommandList = function(type) {
+    var args = validator_.validateArgs(arguments, [
+        {
+            name: 'type',
+            type: types_.ENUM,
+            values: type_.getValues(VoiceControlCommandType),
+            optional: true,
+            nullable: true
+        }
+    ]);
+
+    if (type_.isNullOrUndefined(args.type)) {
+        args.type = VoiceControlCommandType.FOREGROUND;
+    }
+
+    var result = native_.callSync('VoiceControlClient_unsetCommandList', {
+        type: args.type
+    });
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+};
+
+VoiceControlClient.prototype.addResultListener = function(listener) {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'listener', type: types_.FUNCTION }
+    ]);
+
+    return VcResultListener.addListener(
+        args.listener,
+        'VoiceControlClient_addResultListener'
+    );
+};
+
+VoiceControlClient.prototype.removeResultListener = function(id) {
+    if (!type_.isNumber(id)) {
+        throw new WebAPIException(
+            WebAPIException.TYPE_MISMATCH_ERR,
+            'Cannot convert id to int.'
+        );
+    }
+
+    var args = validator_.validateArgs(arguments, [{ name: 'id', type: types_.LONG }]);
+
+    VcResultListener.removeListener(args.id, 'VoiceControlClient_removeResultListener');
+};
+
+VoiceControlClient.prototype.addLanguageChangeListener = function(listener) {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'listener', type: types_.FUNCTION }
+    ]);
+
+    return VcLangListener.addListener(
+        args.listener,
+        'VoiceControlClient_addLanguageChangeListener'
+    );
+};
+
+VoiceControlClient.prototype.removeLanguageChangeListener = function(id) {
+    if (!type_.isNumber(id)) {
+        throw new WebAPIException(
+            WebAPIException.TYPE_MISMATCH_ERR,
+            'Cannot convert id to int.'
+        );
+    }
+
+    var args = validator_.validateArgs(arguments, [{ name: 'id', type: types_.LONG }]);
+
+    VcLangListener.removeListener(
+        args.id,
+        'VoiceControlClient_removeLanguageChangeListener'
+    );
+};
+
+VoiceControlClient.prototype.release = function() {
+    var result = native_.callSync('VoiceControlClient_release', {});
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+    VcLangListener.removeAllListeners();
+    VcResultListener.removeAllListeners();
+};
+
+// Constructor of VoiceControlCommand
+function VoiceControlCommand(command, type) {
+    validator_.isConstructorCall(this, VoiceControlCommand);
+
+    var _command = command;
+    var _type = type;
+
+    if (type_.isNullOrUndefined(_type)) {
+        _type = VoiceControlCommandType.FOREGROUND;
+    }
+
+    Object.defineProperties(this, {
+        command: {
+            enumerable: true,
+            get: function() {
+                return _command;
+            },
+            set: function(value) {
+                _command = value;
+            }
+        },
+        type: {
+            enumerable: true,
+            get: function() {
+                return _type;
+            },
+            set: function(value) {
+                if (
+                    type_.arrayContains(type_.getValues(VoiceControlCommandType), value)
+                ) {
+                    _type = value;
+                }
+            }
+        }
+    });
+}
+
+exports = new VoiceControlClientManager();
+tizen.VoiceControlCommand = VoiceControlCommand;
diff --git a/src/voicecontrol/voicecontrol_client.cc b/src/voicecontrol/voicecontrol_client.cc
new file mode 100644 (file)
index 0000000..5659a1b
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2017 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 "voicecontrol/voicecontrol_client.h"
+#include <voice_control.h>
+#include <voice_control_internal.h>
+#include "voicecontrol/voicecontrol_util.h"
+
+#include <functional>
+
+#include "common/logger.h"
+#include "common/picojson.h"
+#include "common/platform_exception.h"
+#include "common/scope_exit.h"
+#include "common/tools.h"
+
+namespace extension {
+namespace voicecontrol {
+
+VoiceControlClient::VoiceControlClient() : is_result_cb_set(false), is_lang_cb_set(false) {
+  ScopeLogger();
+}
+
+VoiceControlClient::~VoiceControlClient() {
+  ScopeLogger();
+}
+
+common::PlatformResult VoiceControlClient::GetCurrentLanguage(std::string* language) {
+  ScopeLogger();
+
+  char* lang = nullptr;
+  int ret = VC_ERROR_NONE;
+
+  ret = vc_get_current_language(&lang);
+  if (VC_ERROR_NONE != ret) {
+    LoggerE("Fail to get current language");
+    return MakeErrorObject(ret);
+  }
+
+  *language = std::string(lang);
+  free(lang);
+
+  return MakeErrorObject(ret);
+}
+
+common::PlatformResult VoiceControlClient::SetCommandList(const std::vector<picojson::value>& list,
+                                                          const std::string& type) {
+  ScopeLogger();
+
+  int ret = VC_ERROR_NONE;
+  int type_enum = VcConvertCmdType(type);
+
+  vc_cmd_list_h vc_cmd_list = nullptr;
+  SCOPE_EXIT {
+    vc_cmd_list_destroy(vc_cmd_list, true);
+  };
+
+  ret = vc_cmd_list_create(&vc_cmd_list);
+  if (VC_ERROR_NONE != ret) {
+    return MakeErrorObject(ret);
+  }
+
+  for (auto it = list.begin(); it != list.end(); it++) {
+    vc_cmd_h vc_command = nullptr;
+    ret = vc_cmd_create(&vc_command);
+    if (VC_ERROR_NONE != ret) {
+      return MakeErrorObject(ret);
+    }
+
+    std::unique_ptr<std::remove_pointer<vc_cmd_h>::type, int (*)(vc_cmd_h)> ptr(vc_command,
+                                                                                &vc_cmd_destroy);
+
+    ret = vc_cmd_set_command(ptr.get(), (*it).get(COMMAND).get<std::string>().c_str());
+    if (VC_ERROR_NONE != ret) {
+      return MakeErrorObject(ret);
+    }
+
+    ret = vc_cmd_set_type(ptr.get(), VcConvertCmdType((*it).get(TYPE).get<std::string>()));
+    if (VC_ERROR_NONE != ret) {
+      return MakeErrorObject(ret);
+    }
+
+    ret = vc_cmd_list_add(vc_cmd_list, ptr.get());
+    if (VC_ERROR_NONE != ret) {
+      return MakeErrorObject(ret);
+    }
+    ptr.release();
+  }
+
+  ret = vc_set_command_list(vc_cmd_list, type_enum);
+  return MakeErrorObject(ret);
+}
+
+common::PlatformResult VoiceControlClient::UnsetCommandList(const std::string& type) {
+  ScopeLogger();
+
+  int ret = VC_ERROR_NONE;
+  int type_enum = VcConvertCmdType(type);
+
+  ret = vc_unset_command_list(type_enum);
+  return MakeErrorObject(ret);
+}
+
+common::PlatformResult VoiceControlClient::AddResultListener() {
+  ScopeLogger();
+
+  is_result_cb_set = true;
+  return MakeErrorObject(VC_ERROR_NONE);
+}
+
+common::PlatformResult VoiceControlClient::RemoveResultListener() {
+  ScopeLogger();
+
+  is_result_cb_set = false;
+  return MakeErrorObject(VC_ERROR_NONE);
+}
+
+common::PlatformResult VoiceControlClient::AddLanguageChangeListener() {
+  ScopeLogger();
+
+  is_lang_cb_set = true;
+  return MakeErrorObject(VC_ERROR_NONE);
+}
+
+common::PlatformResult VoiceControlClient::RemoveLanguageChangeListener() {
+  ScopeLogger();
+
+  is_lang_cb_set = false;
+  return MakeErrorObject(VC_ERROR_NONE);
+}
+
+bool VoiceControlClient::IsResultListenerSet() {
+  ScopeLogger();
+
+  return is_result_cb_set;
+}
+
+bool VoiceControlClient::IsLanguageChangedListenerSet() {
+  ScopeLogger();
+
+  return is_lang_cb_set;
+}
+
+#undef CHECK_EXIST
+
+}  // namespace voicecontrol
+}  // namespace extension
diff --git a/src/voicecontrol/voicecontrol_client.h b/src/voicecontrol/voicecontrol_client.h
new file mode 100644 (file)
index 0000000..952d334
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017 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 VOICECONTROL_VOICECONTROL_CLIENT_H_
+#define VOICECONTROL_VOICECONTROL_CLIENT_H_
+
+#include <voice_control.h>
+#include "common/extension.h"
+
+namespace extension {
+namespace voicecontrol {
+
+class VoiceControlClient {
+ public:
+  VoiceControlClient();
+  ~VoiceControlClient();
+
+  common::PlatformResult GetCurrentLanguage(std::string* language);
+  common::PlatformResult SetCommandList(const std::vector<picojson::value>& list,
+                                        const std::string& type);
+  common::PlatformResult UnsetCommandList(const std::string& type);
+  common::PlatformResult AddResultListener();
+  common::PlatformResult RemoveResultListener();
+  common::PlatformResult AddLanguageChangeListener();
+  common::PlatformResult RemoveLanguageChangeListener();
+
+  bool IsResultListenerSet();
+  bool IsLanguageChangedListenerSet();
+
+ private:
+  bool is_result_cb_set;
+  bool is_lang_cb_set;
+};
+
+}  // namespace voicecontrol
+}  // namespace extension
+
+#endif  // VOICECONTROL_VOICECONTROL_CLIENT_H_
\ No newline at end of file
diff --git a/src/voicecontrol/voicecontrol_extension.cc b/src/voicecontrol/voicecontrol_extension.cc
new file mode 100644 (file)
index 0000000..66e1f8c
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017 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 "voicecontrol/voicecontrol_extension.h"
+
+#include "voicecontrol/voicecontrol_instance.h"
+
+// This will be generated from voicecontrol_api.js
+extern const char kSource_voicecontrol_api[];
+
+common::Extension* CreateExtension() {
+  return new VoicecontrolExtension;
+}
+
+VoicecontrolExtension::VoicecontrolExtension() {
+  SetExtensionName("tizen.voicecontrol");
+  SetJavaScriptAPI(kSource_voicecontrol_api);
+
+  const char* entry_points[] = {"tizen.VoiceControlCommand", NULL};
+  SetExtraJSEntryPoints(entry_points);
+}
+
+VoicecontrolExtension::~VoicecontrolExtension() {
+}
+
+common::Instance* VoicecontrolExtension::CreateInstance() {
+  return new extension::voicecontrol::VoiceControlInstance;
+}
\ No newline at end of file
diff --git a/src/voicecontrol/voicecontrol_extension.h b/src/voicecontrol/voicecontrol_extension.h
new file mode 100644 (file)
index 0000000..aab4fd3
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 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 VOICECONTROL_VOICECONTROL_EXTENSION_H_
+#define VOICECONTROL_VOICECONTROL_EXTENSION_H_
+
+#include "common/extension.h"
+
+class VoicecontrolExtension : public common::Extension {
+ public:
+  VoicecontrolExtension();
+  virtual ~VoicecontrolExtension();
+
+ private:
+  virtual common::Instance* CreateInstance();
+};
+
+#endif  // VOICECONTROL_VOICECONTROL_EXTENSION_H_
diff --git a/src/voicecontrol/voicecontrol_instance.cc b/src/voicecontrol/voicecontrol_instance.cc
new file mode 100644 (file)
index 0000000..8e59714
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2017 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 "voicecontrol/voicecontrol_instance.h"
+#include <voice_control.h>
+#include <voice_control_internal.h>
+#include "voicecontrol/voicecontrol_client.h"
+#include "voicecontrol/voicecontrol_util.h"
+
+#include <functional>
+
+#include "common/logger.h"
+#include "common/picojson.h"
+#include "common/platform_exception.h"
+#include "common/scope_exit.h"
+#include "common/tools.h"
+
+namespace extension {
+namespace voicecontrol {
+
+namespace {
+// The privileges that are required in Voicecontrol API
+const std::string kPrivilegeVoiceControl = "http://tizen.org/privilege/recorder";
+}  // namespace
+
+using namespace common;
+using namespace extension::voicecontrol;
+
+VoiceControlInstance::VoiceControlInstance() : voice_control_client() {
+  ScopeLogger();
+  using namespace std::placeholders;
+#define REGISTER_SYNC(c, x) \
+  RegisterSyncHandler(c, std::bind(&VoiceControlInstance::x, this, _1, _2));
+  REGISTER_SYNC("VoiceControlClient_getCurrentLanguage", GetCurrentLanguage);
+  REGISTER_SYNC("VoiceControlClient_setCommandList", SetCommandList);
+  REGISTER_SYNC("VoiceControlClient_unsetCommandList", UnsetCommandList);
+  REGISTER_SYNC("VoiceControlClient_addResultListener", AddResultListener);
+  REGISTER_SYNC("VoiceControlClient_removeResultListener", RemoveResultListener);
+  REGISTER_SYNC("VoiceControlClient_addLanguageChangeListener", AddLanguageChangeListener);
+  REGISTER_SYNC("VoiceControlClient_removeLanguageChangeListener", RemoveLanguageChangeListener);
+  REGISTER_SYNC("VoiceControlClient_release", Release);
+  REGISTER_SYNC("VoiceControlClientManager_getVoiceControlClient", GetVoiceControlClient);
+#undef REGISTER_SYNC
+}
+
+VoiceControlInstance::~VoiceControlInstance() {
+  ScopeLogger();
+  int ret = VC_ERROR_NONE;
+  ret = vc_deinitialize();
+  if (VC_ERROR_NONE != ret && VC_ERROR_INVALID_STATE != ret) {
+    LoggerE("Fail to deinitialize voice control, ret(%d)", ret);
+  }
+}
+
+#define CHECK_EXIST(args, name, out)                                         \
+  if (!args.contains(name)) {                                                \
+    ReportError(TypeMismatchException(name + " is required argument"), out); \
+    return;                                                                  \
+  }
+
+void VoiceControlInstance::GetVoiceControlClient(const picojson::value& args,
+                                                 picojson::object& out) {
+  ScopeLogger();
+
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeVoiceControl, &out);
+
+  int ret = VC_ERROR_NONE;
+  vc_state_e state = VC_STATE_NONE;
+  ret = vc_initialize();
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ret = vc_get_state(&state);
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  if (VC_STATE_READY == state) {
+    LoggerD("VoiceControlClient already initialized");
+    ReportSuccess(out);
+    return;
+  }
+
+  ret = vc_set_result_cb(VcResultCb, this);
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ret = vc_set_current_language_changed_cb(VcLanguageChangedCb, this);
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ret = vc_prepare_sync();
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ReportSuccess(out);
+}
+
+void VoiceControlInstance::Release(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  int ret = VC_ERROR_NONE;
+
+  ret = vc_unprepare();
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ret = vc_unset_result_cb();
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ret = vc_unset_current_language_changed_cb();
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ret = vc_deinitialize();
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ReportSuccess(out);
+}
+
+void VoiceControlInstance::GetCurrentLanguage(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  std::string language;
+  common::PlatformResult result = voice_control_client.GetCurrentLanguage(&language);
+
+  if (result.IsSuccess()) {
+    ReportSuccess(picojson::value(language), out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::SetCommandList(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeVoiceControl, &out);
+
+  CHECK_EXIST(args, TYPE, out)
+  CHECK_EXIST(args, LIST, out)
+
+  const std::string& type = args.get(TYPE).get<std::string>();
+  std::vector<picojson::value> list = args.get(LIST).get<picojson::array>();
+
+  common::PlatformResult result = voice_control_client.SetCommandList(list, type);
+
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::UnsetCommandList(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeVoiceControl, &out);
+
+  CHECK_EXIST(args, TYPE, out)
+
+  const std::string& type = args.get(TYPE).get<std::string>();
+
+  common::PlatformResult result = voice_control_client.UnsetCommandList(type);
+
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::AddResultListener(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  common::PlatformResult result = voice_control_client.AddResultListener();
+
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::RemoveResultListener(const picojson::value& args,
+                                                picojson::object& out) {
+  ScopeLogger();
+
+  common::PlatformResult result = voice_control_client.RemoveResultListener();
+
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::AddLanguageChangeListener(const picojson::value& args,
+                                                     picojson::object& out) {
+  ScopeLogger();
+
+  common::PlatformResult result = voice_control_client.AddLanguageChangeListener();
+
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::RemoveLanguageChangeListener(const picojson::value& args,
+                                                        picojson::object& out) {
+  ScopeLogger();
+
+  common::PlatformResult result = voice_control_client.RemoveLanguageChangeListener();
+
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::ReplyAsync(VoiceControlInstance* instance, const std::string& listenerId,
+                                      bool isSuccess, picojson::object& param) {
+  ScopeLogger();
+  param["listenerId"] = picojson::value(listenerId);
+  param["status"] = picojson::value(isSuccess ? "success" : "error");
+
+  /* All callback functions are called by voice control framework */
+  /* Send result from callback to javascript */
+  picojson::value result = picojson::value(param);
+
+  instance->PostMessage(instance, result.serialize().c_str());
+}
+
+/* Define callback functions for voice control */
+void VoiceControlInstance::VcResultCb(vc_result_event_e event, vc_cmd_list_h cmd_list,
+                                      const char* result, void* user_data) {
+  ScopeLogger();
+  VoiceControlInstance* instance = static_cast<VoiceControlInstance*>(user_data);
+
+  if (nullptr != instance && instance->voice_control_client.IsResultListenerSet()) {
+    LoggerD("VcResultCb");
+    picojson::object param = picojson::object();
+    param["event"] =
+        picojson::value(((event == VC_RESULT_EVENT_RESULT_SUCCESS) ? "SUCCESS" : "FAILURE"));
+
+    int len = 0;
+    int ret = VC_ERROR_NONE;
+
+    ret = vc_cmd_list_get_count(cmd_list, &len);
+    if (VC_ERROR_NONE != ret) {
+      LoggerE("Fail to get the count of the result list");
+      return;
+    }
+
+    ret = vc_cmd_list_first(cmd_list);
+    if (VC_ERROR_NONE != ret) {
+      LoggerE("Fail to get the first element of the result list");
+    }
+
+    picojson::array& value_vector =
+        param.insert(std::make_pair("list", picojson::value(picojson::array(len))))
+            .first->second.get<picojson::array>();
+    param["results"] = picojson::value(result);
+
+    for (int i = 0; VC_ERROR_NONE == ret && i < len; i++) {
+      LoggerD("Current (%d), Count (%d)", i, len);
+      vc_cmd_h vc_command = nullptr;
+      char* command = nullptr;
+      SCOPE_EXIT {
+        free(command);
+      };
+
+      ret = vc_cmd_list_get_current(cmd_list, &vc_command);
+      if (VC_ERROR_NONE != ret) {
+        break;
+      }
+
+      ret = vc_cmd_get_command(vc_command, &command);
+      if (VC_ERROR_NONE != ret) {
+        break;
+      }
+
+      if (nullptr != command) {
+        LoggerD("Command (%s)", command);
+        value_vector[i] = picojson::value(command);
+      }
+
+      ret = vc_cmd_list_next(cmd_list);
+    }
+
+    ReplyAsync(instance, ON_RESULT, true, param);
+  }
+}
+
+void VoiceControlInstance::VcLanguageChangedCb(const char* previous, const char* current,
+                                               void* user_data) {
+  ScopeLogger();
+  VoiceControlInstance* instance = static_cast<VoiceControlInstance*>(user_data);
+  if (nullptr != instance && instance->voice_control_client.IsLanguageChangedListenerSet()) {
+    LoggerD("VcLanguageChangedCb");
+    picojson::object param = picojson::object();
+    param["previous"] = picojson::value(previous);
+    param["current"] = picojson::value(current);
+
+    ReplyAsync(instance, ON_LANG, true, param);
+  }
+}
+
+#undef CHECK_EXIST
+
+}  // namespace voicecontrol
+}  // namespace extension
diff --git a/src/voicecontrol/voicecontrol_instance.h b/src/voicecontrol/voicecontrol_instance.h
new file mode 100644 (file)
index 0000000..03d2aac
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 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 VOICECONTROL_VOICECONTROL_INSTANCE_H_
+#define VOICECONTROL_VOICECONTROL_INSTANCE_H_
+
+#include <voice_control_common.h>
+
+#include "common/extension.h"
+#include "voicecontrol/voicecontrol_client.h"
+
+namespace extension {
+namespace voicecontrol {
+
+class VoiceControlInstance : public common::ParsedInstance {
+ public:
+  VoiceControlInstance();
+  virtual ~VoiceControlInstance();
+
+ private:
+  void GetVoiceControlClient(const picojson::value& args, picojson::object& out);
+  void Release(const picojson::value& args, picojson::object& out);
+
+  void GetCurrentLanguage(const picojson::value& args, picojson::object& out);
+  void SetCommandList(const picojson::value& args, picojson::object& out);
+  void UnsetCommandList(const picojson::value& args, picojson::object& out);
+  void AddResultListener(const picojson::value& args, picojson::object& out);
+  void RemoveResultListener(const picojson::value& args, picojson::object& out);
+  void AddLanguageChangeListener(const picojson::value& args, picojson::object& out);
+  void RemoveLanguageChangeListener(const picojson::value& args, picojson::object& out);
+
+  static void VcLanguageChangedCb(const char* previous, const char* current, void* user_data);
+  static void VcResultCb(vc_result_event_e event, vc_cmd_list_h cmd_list, const char* result,
+                         void* user_data);
+  static void ReplyAsync(VoiceControlInstance* instance, const std::string& listenerId,
+                         bool isSuccess, picojson::object& param);
+
+  VoiceControlClient voice_control_client;
+};
+
+}  // namespace voicecontrol
+}  // namespace extension
+
+#endif  // VOICECONTROL_VOICECONTROL_INSTANCE_H_
\ No newline at end of file
diff --git a/src/voicecontrol/voicecontrol_util.cc b/src/voicecontrol/voicecontrol_util.cc
new file mode 100644 (file)
index 0000000..d244e21
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017 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 "voicecontrol/voicecontrol_util.h"
+#include <voice_control.h>
+
+namespace extension {
+namespace voicecontrol {
+
+const std::string& MakeErrorMessage(const int ret) {
+  ScopeLogger();
+  switch (ret) {
+    case VC_ERROR_NONE:
+      return NO_ERROR;
+    case VC_ERROR_INVALID_PARAMETER:
+      return INVALID_PARAMETER;
+    case VC_ERROR_OUT_OF_MEMORY:
+      return OUT_OF_MEMORY;
+    case VC_ERROR_OPERATION_FAILED:
+    case VC_ERROR_INVALID_STATE:
+      return OPERATION_FAILED;
+    case VC_ERROR_PERMISSION_DENIED:
+      return PERMISSION_DENIED;
+    case VC_ERROR_NOT_SUPPORTED:
+      return NOT_SUPPORTED;
+    default:
+      return OPERATION_FAILED;
+  }
+}
+
+common::PlatformResult MakeErrorObject(const int ret) {
+  ScopeLogger();
+  std::string message = MakeErrorMessage(ret);
+  switch (ret) {
+    case VC_ERROR_NONE:
+      return common::PlatformResult(common::ErrorCode::NO_ERROR);
+    case VC_ERROR_INVALID_PARAMETER:
+      return common::PlatformResult(common::ErrorCode::INVALID_VALUES_ERR, message);
+    case VC_ERROR_PERMISSION_DENIED:
+      return common::PlatformResult(common::ErrorCode::SECURITY_ERR, message);
+    case VC_ERROR_NOT_SUPPORTED:
+      return common::PlatformResult(common::ErrorCode::NOT_SUPPORTED_ERR, message);
+    default:
+      return common::PlatformResult(common::ErrorCode::ABORT_ERR, message);
+  }
+}
+
+int VcConvertCmdType(const std::string& type) {
+  ScopeLogger("%s", type.c_str());
+  // TODO add switch here when also other types of command will be also supported.
+  // For now, only foreground is supported, we return it as the default value.
+  return VC_COMMAND_TYPE_FOREGROUND;
+}
+
+}  // namespace voicecontrol
+}  // namespace extension
diff --git a/src/voicecontrol/voicecontrol_util.h b/src/voicecontrol/voicecontrol_util.h
new file mode 100644 (file)
index 0000000..a8fff25
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 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 VOICECONTROL_VOICECONTROL_UTIL_H_
+#define VOICECONTROL_VOICECONTROL_UTIL_H_
+
+#include "common/extension.h"
+
+namespace extension {
+namespace voicecontrol {
+
+namespace {
+/* Error message text */
+const std::string NO_ERROR = "No error";
+const std::string INVALID_PARAMETER = "Invalid parameter!";
+const std::string OUT_OF_MEMORY = "Out of memory!";
+const std::string OPERATION_FAILED = "Operation failed!";
+const std::string PERMISSION_DENIED = "Permission denied!";
+const std::string NOT_SUPPORTED = "Not supported!";
+
+/* Parameter name */
+const std::string CALLBACK_ID = "callbackId";
+const std::string TYPE = "type";
+const std::string LIST = "list";
+const std::string COMMAND = "command";
+
+/* Voice control command type */
+const std::string FOREGROUND = "FOREGROUND";
+
+/* Listener types on javascript */
+const std::string ON_RESULT = "onresult";
+const std::string ON_LANG = "onlanguagechanged";
+}
+
+const std::string& MakeErrorMessage(const int ret);
+common::PlatformResult MakeErrorObject(const int ret);
+int VcConvertCmdType(const std::string& type);
+
+}  // namespace voicecontrol
+}  // namespace extension
+
+#endif  // VOICECONTROL_VOICECONTROL_UTIL_H_
\ No newline at end of file
index 5154554..bbd61c0 100644 (file)
@@ -586,9 +586,10 @@ TizenResult WidgetServiceInstance::SendContent(picojson::object const& args) {
     LogAndReturnTizenError(common::AbortError(ret), ("bundle_add() failed"));
   }
 
-  ret = widget_service_trigger_update(widget_id.c_str(), instance_id.c_str(), data, force);
-  if (WIDGET_ERROR_NONE != ret) {
-    LogAndReturnTizenError(WidgetServiceUtils::ConvertErrorCode(ret),
+  int ret_widget =
+      widget_service_trigger_update(widget_id.c_str(), instance_id.c_str(), data, force);
+  if (WIDGET_ERROR_NONE != ret_widget) {
+    LogAndReturnTizenError(WidgetServiceUtils::ConvertErrorCode(ret_widget),
                            ("widget_service_trigger_update() failed"));
   }
 
@@ -620,11 +621,11 @@ TizenResult WidgetServiceInstance::GetContent(picojson::object const& args,
       bundle_free(bundle_data);
     };
 
-    ret = widget_service_get_content_of_widget_instance(widget_id.c_str(), instance_id.c_str(),
-                                                        &bundle_data);
-    if (WIDGET_ERROR_NONE != ret) {
+    int ret_widget = widget_service_get_content_of_widget_instance(
+        widget_id.c_str(), instance_id.c_str(), &bundle_data);
+    if (WIDGET_ERROR_NONE != ret_widget) {
       LoggerE("widget_service_get_content_of_widget_instance() failed");
-      this->Post(token, WidgetServiceUtils::ConvertErrorCode(ret));
+      this->Post(token, WidgetServiceUtils::ConvertErrorCode(ret_widget));
       return;
     }